Minimalistic SLIP model

last edits:

  • June 18th, 2013 Moritz Maus, worked on continous prediction (here)
  • June 25th, 2013 Moritz Maus, started outline of "phase computation for SLIP" (here)
  • June 26th, 2013 Moritz Maus, reworked section 4 (-> functions) so that it can be reused in section 9
  • June 28th, 2013 Moritz Maus, created improved autonomous simulation based on human-derived reference motion and control maps
  • July 1st, 2013 Moritz Maus, moved parts of code into modules and cont'd working on section 9 (here)
  • July 2nd, 2013 Moritz Maus, re-worked Floquet model prediction (here)
  • July 4th, 2013 Moritz Maus, worked on continuous CoM prediction
  • July 5th, 2013 Moritz Maus, worked on phase error bug (solved)
  • July 8th, 2013 Moritz Maus, added phase to (stable) SLIP simulation; added "[CoM; last SLIP params]" to model tests (section 3.7)
  • July 9th, 2013 Moritz Maus, tested two sanity checks for the manuscripts

continue here:

TODO:

  • There is an error in / a problem with the "initial" map which maps apex to some fixed phase shortly after apex: it is not close enough to "1"
  • clean up Section 9
  • compute phase for unstable SLIP

prerequisites:

Requires IPython to run in "pylab" mode. If this is not the case, at least insert
from pylab import *
or
%pylab inline
somewhere

synopsis:

This notebook continues scientific investigations from the original "AnkleSLIP" notebook.
It has been splitted to regain the general overview.

This script tries to identify a minimalistic SLIP extension (e.g., Ankle-Y-position only).
Requirements:

  • System must be self-contained
  • System must have eigenvalues similar to original data
  • System must be approximately as predictable as "full ankle-SLIP"

Step 0: configure notebook

to content
Select subject and details of computation


In [23]:
# define and import data
subject = 2  #available subjects: 1,2,3,7. Other subjects have comparatively bad data quality
ttype = 1 # 1: free running, 2: metronome running (data incomplete!)
n_factors = 3 # 1-5 factors to predict SLIP parameters
exclude_IC_from_factors = False # exclude the initial conditions from kinematic state 
                               #prior to identifying SLIP parameter predictors?

# select ankle-SLIP instead of "factors without CoM state" ?
select_ankle_SLIP = True

# to compute periodic SLIP orbit: average over parameters or initial conditions?
po_average_over_IC = True

Step 1: import data

to content


In [24]:
import mutils.io as mio
reload(mio)
import mutils.misc as mi
import os
import sys
import re

# load kinematic data
k = mio.KinData()
k.load(subject, ttype)
k.selection = ['r_anl_y - com_y', 'l_anl_y - com_y', 'com_z']

SlipData = [mi.Struct(mio.mload('../data/2013-newSlip/SLIP_s%it%ir%i.dict' % (subject, ttype, rep)))
           for rep in k.reps]

indices_right = [mi.upper_phases(d.phases[:-1], sep=0, return_indices=True) for d in SlipData]
indices_left = [mi.upper_phases(d.phases[:-1], sep=pi, return_indices=True) for d in SlipData]
starts_right = [idxr[0] < idxl[0] for idxr, idxl in zip(indices_right, indices_left)]
param_right = [ vstack(d.P)[idxr, :] for d, idxr in zip(SlipData, indices_right)]
param_left = [ vstack(d.P)[idxl, :] for d, idxl in zip(SlipData, indices_left)]
IC_right = [ vstack(d.IC)[idxr, :] for d, idxr in zip(SlipData, indices_right)]
IC_left = [ vstack(d.IC)[idxl, :] for d, idxl in zip(SlipData, indices_left)]

In [25]:
# additional step parameters: step time, minimal apex height
TR = [vstack(d.T)[idxr, :] for d, idxr in zip(SlipData, indices_right)]
TL = [vstack(d.T)[idxl, :] for d, idxl in zip(SlipData, indices_left)]
yminR = [vstack(d.ymin)[idxr, :] for d, idxr in zip(SlipData, indices_right)]
yminL = [vstack(d.ymin)[idxl, :] for d, idxl in zip(SlipData, indices_left)]

Step 2: test consistence (run SLIP)

to content


In [26]:
#select any data
import models.sliputil as su
dat = SlipData[2]
stepnr = 32

print "simulation:",  su.finalState(dat.IC[stepnr], dat.P[stepnr], {'m' : dat.mass, 'g': dat.g})
print '==================='
print "experiment:", dat.IC[stepnr + 1]


simulation: [ 1.01547296  2.81971149 -0.01139514]
===================
experiment: [ 1.01547296  2.81971211 -0.01139514]

In [27]:
reload(mio)

# New: Each section gets its own data container. 

# find minimal predictors
import mutils.statistics as st
import mutils.FDatAn as fda

# set apex data
# *NOTE* the first three labels have to be "com_x", "com_y", "com_z". If you edit this, make sure to edit the cell where data
# are further processed...
k.selection = [ 'com_x', 'com_y', 'com_z',
             'r_anl_y - com_y', 'r_anl_x - com_x', 'r_mtv_z - r_anl_z', 'r_mtv_x - r_anl_x', 'r_kne_y - com_y',
             'r_elb_y - com_y', 'r_elb_x - com_x', 'r_wrl_z - com_z', 'r_wrl_x - com_x', 'cvii_y - com_y',
             'l_anl_y - com_y', 'l_anl_x - com_x', 'l_mtv_z - l_anl_z', 'l_mtv_x - l_anl_x', 'l_kne_y - com_y',
             'l_elb_y - com_y', 'l_elb_x - com_x', 'l_wrl_z - com_z', 'l_wrl_x - com_x', ]

# sep = 0 -> right leg will touchdown next
# sep = pi -> right leg will touchdown next

# always exclude last apex - there are no SLIP parameters defined for it!
kin_right = k.get_kin_apex( [mi.upper_phases(d.phases[:-1], sep=0) for d in SlipData],)
kin_left  = k.get_kin_apex( [mi.upper_phases(d.phases[:-1], sep=pi) for d in SlipData],)

Build common data set for kinematic and SLIP data

Definition: each stride starts with a right step


In [69]:
# build common dataset
import mutils.io as mio
from  mutils.io import build_dataset
reload(mio)
import mutils.misc as mi
import mutils.FDatAn as fda

In [71]:



---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-71-ddd693962455> in <module>()
----> 1 ws9.k9.display()

AttributeError: 'KinData' object has no attribute 'display'

In [72]:
# load kinematic data

if False: # take previously defined data?
    subject = 3
    ttype = 1
    k = mio.KinData()
    k.load(subject, ttype)
    k.selection = ['com_x', 'com_y', 'com_z', 'r_anl_y - com_y', 'l_anl_y - com_y', 'com_z']
    SlipData = [mi.Struct(mio.mload('../data/2013-newSlip/SLIP_s%it%ir%i.dict' % (subject, ttype, rep)))
               for rep in k.reps]

d3orig = build_dataset(k, SlipData) # the d3 "original" workspace


all_IC_r = d3orig.all_IC_r
all_IC_l = d3orig.all_IC_l
all_param_r = d3orig.all_param_r
all_param_l = d3orig.all_param_l
all_kin_r = d3orig.all_kin_r
all_kin_l = d3orig.all_kin_l
all_phases_r = d3orig.all_phases_r
all_phases_l = d3orig.all_phases_l

param_right = d3orig.param_right
param_left = d3orig.param_left
IC_right = d3orig.IC_right
IC_left = d3orig.IC_left

TR = d3orig.TR
TL = d3orig.TL
yminR = d3orig.yminR
yminL = d3orig.yminL

kin_labels = d3orig.kin_labels

# copy to section 3 data container
d3 = mio.saveable() # this is a general container class that supplies a "save" and "load" functionality.
d3.kin_labels = kin_labels
d3.IC_r = all_IC_r
d3.IC_l = all_IC_l
d3.param_r = all_param_r
d3.param_l = all_param_l
d3.kin_r = all_kin_r
d3.kin_l = all_kin_l
d3.mass = mean([d.mass for d in SlipData])
d3orig.mass = mean([d.mass for d in SlipData])

Step 3.1 Re-test consistency of SLIP data

step 3: find minimal predictors
to content

NOTE Here, the mass is not exactly the same as in the parameter calculations. Thus, minor deviations may occur.


In [30]:
stepnr = 1299
mass = mean([d.mass for d in SlipData])
# su.finalState actually performs a one-step integration of SLIP
print "simres  [right step]:", su.finalState(d3orig.all_IC_r[stepnr, :], d3orig.all_param_r[stepnr, :], {'m' : d3orig.mass, 'g' : -9.81})
print "subsequent left apex:", d3orig.all_IC_l[stepnr, :]
print "==========="
print "simres    [left step]:", su.finalState(d3orig.all_IC_l[stepnr, :], d3orig.all_param_l[stepnr, :], {'m' : d3orig.mass, 'g' : -9.81})
print "subsequent right apex:", d3orig.all_IC_r[stepnr + 1, :]


simres  [right step]: [ 1.00439721  2.93393925 -0.04731663]
subsequent left apex: [ 1.0047793   2.93268126 -0.04730393]
===========
simres    [left step]: [ 1.00445095  2.94246695  0.06573004]
subsequent right apex: [ 1.00481933  2.94125541  0.06572403]

Step 3.2 Compute predictors

step 3: find minimal predictors
to content

first: prepare data


In [73]:
# detrend - look at residuals!
dt_kin_r = fda.dt_movingavg(all_kin_r, 30)
dt_kin_l = fda.dt_movingavg(all_kin_l, 30)
dt_param_r = fda.dt_movingavg(all_param_r, 30)
dt_param_l = fda.dt_movingavg(all_param_l, 30)
dt_IC_r = fda.dt_movingavg(all_IC_r, 30)
dt_IC_l = fda.dt_movingavg(all_IC_l, 30)

# use the *same* values for normalization for left and right!
# yes, it's 'sdt', not 'std': "Scores of DeTrented" ...
sdt_kin_r = dt_kin_r / std(dt_kin_r, axis=0)
sdt_kin_l = dt_kin_l / std(dt_kin_r, axis=0)
sdt_param_r = dt_param_r / std(dt_param_r, axis=0)
sdt_param_l = dt_param_l / std(dt_param_r, axis=0)

sdt_kin_r -= mean(sdt_kin_r, axis=0)
sdt_kin_l -= mean(sdt_kin_l, axis=0)
sdt_param_r -= mean(sdt_param_r, axis=0)
sdt_param_l -= mean(sdt_param_l, axis=0)

sdt_kin_r_noIC = hstack([sdt_kin_r[:,1:20],sdt_kin_r[:, 22:]])
sdt_kin_l_noIC = hstack([sdt_kin_l[:,1:20],sdt_kin_l[:, 22:]])

# append data to section 3 workspace
d3.s_kin_r = sdt_kin_r
d3.s_kin_l = sdt_kin_l
d3.s_param_r = sdt_param_r
d3.s_param_l = sdt_param_l
d3.s_kin_r_noIC = sdt_kin_r_noIC
d3.s_kin_l_noIC = sdt_kin_l_noIC

d3.dt_kin_r = dt_kin_r
d3.dt_kin_l = dt_kin_l
d3.dt_param_r = dt_param_r
d3.dt_param_l = dt_param_l
d3.dt_IC_r = dt_IC_r
d3.dt_IC_l = dt_IC_l

In [83]:
print dt_kin_r.shape, dt_param_r.shape
print dt_kin_l.shape, dt_param_l.shape


(1957, 45) (1957, 5)
(1957, 45) (1957, 5)

rotate predictors such that only 3 have non-zero components on CoM state


In [84]:
## TESTING - DELETE ME!
#sdt_kin_r.shape
s_IC_r = fda.dt_movingavg(d3.IC_r, 30) 
s_IC_r /= std(s_IC_r, axis=0)
s_kin_reord_r = hstack([s_IC_r, d3.s_kin_r_noIC]) # sdt_kin_r[:, [0,20,21]], sdt_kin_r_noIC])
p1 = dot(d3.s_param_r.T, pinv(s_kin_reord_r.T))
#p2, _,_, _ = lstsq(sdt_kin_r, sdt_param_r, )
#p2 = p2.T
#allclose(p1, p2) # results in "True"
u,s,v = svd(p1, full_matrices = False)
# gram-schmidtify v

In [76]:
qv,rv = qr(v) # rv spans the same subspace as v
# TEST:
#prv = dot(rv.T, rv) # projector on "rv" subspace
#print allclose(prv, dot(prv, prv)) # True -> is a projector
#print allclose(dot(prv, v.T), v.T) # True -> projects into the same subspace as v
rv2 = rv.copy()
# make "identity" 3x3 block
rv2[1,:] -= rv2[2, :] * rv2[1,2] / rv2[2,2]
rv2[0,:] -= rv2[1, :] * rv2[0,1] / rv2[1,1]
rv2[0,:] -= rv2[2, :] * rv2[0,2] / rv2[2,2]

p2 = dot(rv2[3:,:].T, rv2[3:, :])
ap = eye(41) - p2

rv2[:3,:] = dot(ap,rv2[:3,:].T).T

figure()
pcolor(rv2)
colorbar()
clim(-1,1)


---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-76-ad73dfff57a8> in <module>()
     11 
     12 p2 = dot(rv2[3:,:].T, rv2[3:, :])
---> 13 ap = eye(41) - p2
     14 
     15 rv2[:3,:] = dot(ap,rv2[:3,:].T).T

ValueError: operands could not be broadcast together with shapes (41,41) (45,45) 

Step 3.3: select factors and models

step 3: find minimal predictors
to content

Select factors and dimensions of reduced model(s)


In [78]:
# parameter to predict. select [0,1,2,4] for 2D-SLIP (excluding beta), or [0,1,2,3,4] for full 3D SLIP
p2D_r = sdt_param_r[:, [0,1,2,3,4]]
p2D_l = sdt_param_l[:, [0,1,2,3,4]]

In [92]:



Out[92]:
array([[ 0.06076773, -0.08573386,  0.90400627],
       [ 0.48072825, -1.12943208,  0.22907192],
       [ 0.09668203, -0.331898  , -0.14521759],
       ..., 
       [ 0.37165506, -1.09773904, -0.3026212 ],
       [-0.12118271,  0.0091947 , -1.689281  ],
       [ 0.43662834,  0.21455861, -0.17666716]])

In [91]:
# Here, the main predictors ("directions") are computed. This is computationally quite fast
if exclude_IC_from_factors:
    facs_r = st.find_factors(sdt_kin_r_noIC.T, p2D_r.T, k=n_factors)
    facs_l = st.find_factors(sdt_kin_l_noIC.T, p2D_l.T, k=n_factors)

    fscore_r = dot(facs_r.T, sdt_kin_r_noIC.T).T
    fscore_l = dot(facs_l.T, sdt_kin_l_noIC.T).T

else:
    facs_r = st.find_factors(sdt_kin_r.T, p2D_r.T, k=n_factors)
    facs_l = st.find_factors(sdt_kin_l.T, p2D_l.T, k=n_factors)
    
    # project data on lower dimensional subspace (do not take to full space again)
    fscore_r = dot(facs_r.T, sdt_kin_r.T).T
    fscore_l = dot(facs_l.T, sdt_kin_l.T).T

Select one of these reduced models


In [37]:
# reduced model: 6D state, 3 predictors
#reddat_r = hstack([fscore_r, dt_IC_r])
#reddat_l = hstack([fscore_l, dt_IC_l])

# form a model that *only* conists of parts of the "full" data (*excatly* the same data),
# which however may be projected to some axes
IC_r_from_dt = sdt_kin_r[:,[0, 20, 21]]   # CoM height and horizontal plane velocities
IC_l_from_dt  = sdt_kin_l[:,[0, 20, 21]]
reddat_r = hstack([fscore_r, IC_r_from_dt])
reddat_l = hstack([fscore_l, IC_l_from_dt])

# add data to section 3 data structure
d3.s_IC_r = IC_r_from_dt
d3.s_IC_l = IC_l_from_dt

# reddat_r = fscore_r
# reddat_l = fscore_l

Step 3.4: test predictive capabilities for SLIP parameter

step 3: find minimal predictors
to content


In [38]:
# "select the initial conditions from full state information" - matrix
# this matrix only makes sense if exclude_IC_from_factors is set to False!

d3.display()

if not exclude_IC_from_factors:
    IC_sel = zeros((41, 3))
    IC_sel[0, 0] = 1
    IC_sel[20, 1] = 1
    IC_sel[21, 2] = 1
    
    rm_selector_r = hstack([facs_r, IC_sel])
    rm_selector_l = hstack([facs_l, IC_sel])


IC_l            array (1957, 3)   
IC_r            array (1957, 3)   
_saveables      list (8)   
dt_IC_l         array (1957, 3)   
dt_IC_r         array (1957, 3)   
dt_kin_l        array (1957, 41)   
dt_kin_r        array (1957, 41)   
dt_param_l      array (1957, 5)   
dt_param_r      array (1957, 5)   
kin_l           array (1957, 41)   
kin_labels      list (41)   
kin_r           array (1957, 41)   
mass            <type 'numpy.float64'>         
param_l         array (1957, 5)   
param_r         array (1957, 5)   
s_IC_l          array (1957, 3)   
s_IC_r          array (1957, 3)   
s_kin_l         array (1957, 41)   
s_kin_l_noIC    array (1957, 38)   
s_kin_r         array (1957, 41)   
s_kin_r_noIC    array (1957, 38)   
s_param_l       array (1957, 5)   
s_param_r       array (1957, 5)   

Test predictive capabilities for SLIP parameters of full and reduced models

Note: to make a quick sanity check, you can change the "out-of-sample" prediction parameter to "False" to get in-sample prediction


In [39]:
predict_oos = True
# select reduced models as a real subset of the full kinematic state at apex
if not exclude_IC_from_factors:
    # use a real projection of the data!
    reddat_r = dot(rm_selector_r.T, sdt_kin_r.T).T
    reddat_l = dot(rm_selector_l.T, sdt_kin_l.T).T

#p2D_r = p2D_r - mean(p2D_r, axis=0)
#sdt_kin_r = sdt_kin_r - mean(sdt_kin_r, axis=0)

res1 = st.predTest(reddat_r, p2D_r, out_of_sample=predict_oos, rcond=1e-7)
res2 = st.predTest(sdt_kin_r, p2D_r, out_of_sample=predict_oos, rcond=1e-7)

res3 = st.predTest(reddat_l, p2D_l,  out_of_sample=predict_oos, rcond=1e-7)
res4 = st.predTest(sdt_kin_l, p2D_l, out_of_sample=predict_oos, rcond=1e-7)

figure(figsize=(12,6))
subplot(1,2,1)
b1 = boxplot(res1)
b2 = boxplot(res2)
mi.recolor(b1, 'r')
mi.recolor(b2, 'k')
xticks(arange(5) + 1)
gca().set_xticklabels(['k', r'$\alpha$', r'L$_0$', r'$\beta$', r'$\delta$E'], fontsize=16)
xlabel('predicted variable')
ylabel('relative remaining variance')
ylim(0, 1.05)
title('right step SLIP params\nred: reduced model,\nblack: full kinematic state')
subplot(1,2,2)
b1 = boxplot(res3)
b2 = boxplot(res4)
mi.recolor(b1, 'r')
mi.recolor(b2, 'k')
xticks(arange(5) + 1)
gca().set_xticklabels(['k', r'$\alpha$', r'L$_0$', r'$\beta$', r'$\delta$E'], fontsize=16)
xlabel('predicted variable')
ylabel('relative remaining variance')
ylim(0, 1.05)
title('left step SLIP params\nred: reduced model,\nblack: full kinematic state')

draw()


Step 3.5: Test self-predictability of the model

step 3: find minimal predictors
to content

Note: to make a quick sanity check, you can change the "out-of-sample" prediction parameter to "False" to get in-sample prediction


In [40]:
# test self-consistency

oos_pred = True # out of sample prediction?

# predict
res1 = st.predTest(reddat_r, reddat_l, out_of_sample=oos_pred, rcond=1e-7)
res2 = st.predTest(sdt_kin_r, reddat_l, out_of_sample=oos_pred, rcond=1e-7)

res3 = st.predTest(reddat_l[:-1, :], reddat_r[1:, :], out_of_sample=oos_pred, rcond=1e-7)
res4 = st.predTest(sdt_kin_l[:-1, :], reddat_r[1:, :], out_of_sample=oos_pred, rcond=1e-7)


figure(figsize=(16,8))
subplot(1,2,1)
b1 = boxplot(res1)
b2 = boxplot(res2)
mi.recolor(b1, 'r')
mi.recolor(b2, 'k')
ylim(0, 1.05)
xticks(arange(res3.shape[1]) + 1)
gca().set_xticklabels(['factor ' + str(nr + 1) for nr in arange(res1.shape[1] - 3)] +
      ['height', 'horiz. speed', 'lat. speed'], rotation=45)
title('predicting left apex state\nred: reduced model, black: full model')
ylabel('relative remaining variance')

subplot(1,2,2)
b1 = boxplot(res3)
b2 = boxplot(res4)
mi.recolor(b1, 'r')
mi.recolor(b2, 'k')
ylim(0, 1.05)
xticks(arange(res3.shape[1]) + 1)
gca().set_xticklabels(['factor ' + str(nr + 1) for nr in arange(res1.shape[1] - 3)] +
      ['height', 'horiz. speed', 'lat. speed'], rotation=45)
title('predicting left apex state\nred: reduced model, black: full model')
ylabel('relative remaining variance')

draw()


Step 3.6: Compute (only) eigenvalues of full and reduced Floquet models

step 3: find minimal predictors
to content


In [41]:
# eigenvalue analyis

# full model
_, maps_1, _ = fda.fitData(sdt_kin_r, sdt_kin_l, nps=1, nrep=200, rcond=1e-7)
_, maps_2, _ = fda.fitData(sdt_kin_l[:-1, :], sdt_kin_r[1:, :], nps=1, nrep=200, rcond=1e-7, )
maps_full = [dot(m1, m2) for m1, m2 in zip(maps_1, maps_2)]

# reduced model
_, maps_1, _ = fda.fitData(reddat_r, reddat_l, nps=1, nrep=200, rcond=1e-7)
_, maps_2, _ = fda.fitData(reddat_l[:-1, :], reddat_r[1:, :], nps=1, nrep=200, rcond=1e-7, )
maps_red = [dot(m1, m2) for m1, m2 in zip(maps_1, maps_2)]

In [42]:
import fmalibs.util as ut

vi_full = ut.VisEig(127, False)
for A in maps_full:
    vi_full.add(eig(A)[0])

vi_red = ut.VisEig(127, False)
for A in maps_red:
    vi_red.add(eig(A)[0])

Enhance number of sections per stride for Floquet model


In [43]:
nps = 30 # number of sections per stride
map_sections = [0, 8, 15, 23] # select some sections for which mappings should be computed
map_sections = [0, 5, 10, 15, 20, 25] # select some sections for which mappings should be computed
#map_sections = [0, 7, 13, 19,25] # select some sections for which mappings should be computed
#map_sections = [0, 10, 20] # select some sections for which mappings should be computed
k_n = fda.dt_movingavg(k.make_1D(nps=nps)[:, 2 * nps:], 30) # exclude horizontal CoM position
k_n -= mean(k_n, axis=0)
k_n /= std(k_n, axis=0)
maps_pt, maps_full, idcs = fda.fitData(k_n[:-1, :], k_n[1:, :], nps=nps, sections=map_sections, nrep=200, rcond=1e-7 )

In [44]:
# compute stride maps from sections maps
# note: the correct order in the product of maps is  map_n * map_(n-1) * ... * map_1
# otherwise, the resulting matrix is not a propagator
# -> reverse ordering of maps
all_maps = [reduce(dot, maps[::-1]) for maps in zip(*maps_pt)]

vi3 = ut.VisEig(127, False)
for A in all_maps:
    vi3.add(eig(A)[0])

Step 3.7: test different explicit models:

step 3: find minimal predictors
step 3.7.1: model 1 (x,y,vx,vy) both ankles
step 3.7.2: model 2 (x,y) both ankles, (vx, vy) swing leg (which swing leg?)
step 3.7.2: model 3 (x,y,vx,vy) of swing ankle only
to content

Shai would like to know the predictive ability with the states reduced as follows:

  1. 14D: x,y,vx,vy of ankles (8D) + (5D) COM (with one of 6D is identically 0)
  2. 12D: x,y of both ankles (4D) + vx,vy of swing ankle (2D) + (5D) COM
  3. 10D: x,y,vx,vy of swing ankle only (4D) + (5D) COM

NOTE The state definition has changed: The absolute horizontal position has been removed.
On the one hand, this is because I'd expect a completely different behavior there (focussed not to leave the treadmill instead of getting back to some periodic orbit). On the other hand, if we include the absolute position in the state, the parameter calculation method is no longer valid. In fact, SLIP cannot match arbitrary data in all 6 CoM state space dimensions in a single step (Carver's result).

things to predict:

  1. SLIP parameters
  2. CoM state (actually: this is included in the autonomy-prediction)
  3. Autonomy of system

NOTE There are two different approaches to test the 1-stride autonomy:

  1. Predict state after 1 stride directly from input data (here: "1 stage prediction")
  2. Predict state after 1 step, use prediction to predict state after next step (here: "2 stages prediction").

NOTE The coordinate system here is:
x - lateral
y - anterior
z - vertical

shortcut to get the data (testing) - skip running the whole notebook until here.


In [19]:
import mutils.FDatAn as fda
import mutils.io as mio
import mutils.misc as mi
k3 = mio.KinData()
subject, ttype = 3, 1

k3.load(subject, ttype) # subject in [1,2,3,7], ttype=1

k3.selection = [ 'com_x', 'com_y', 'com_z',
             'r_anl_y - com_y', 'r_anl_x - com_x', 'r_mtv_z - r_anl_z', 'r_mtv_x - r_anl_x', 'r_kne_y - com_y',
             'r_elb_y - com_y', 'r_elb_x - com_x', 'r_wrl_z - com_z', 'r_wrl_x - com_x', 'cvii_y - com_y',
             'l_anl_y - com_y', 'l_anl_x - com_x', 'l_mtv_z - l_anl_z', 'l_mtv_x - l_anl_x', 'l_kne_y - com_y',
             'l_elb_y - com_y', 'l_elb_x - com_x', 'l_wrl_z - com_z', 'l_wrl_x - com_x', 
             'r_anl_z - com_z', 'l_anl_z - com_z',
             'r_sia_y - l_sia_y']

SlipData = [mi.Struct(mio.mload('../data/2013-newSlip/SLIP_s%it%ir%i.dict' % (subject, ttype, rep)))
           for rep in k3.reps]
kdata_full = build_dataset(k3, SlipData)

In [336]:
# common code: make predictions and create figures

import mutils.statistics as st
import mutils.misc as mi
# this function requires d3 - data object in its closure
def test_model(kdata_r, kdata_l, kdata_full, side="r"):
    """
    This function performs the prediction tests and creates the
    corrsponding figures displaying the results.
    
    :args:
        in_dat (nxd array): data to predict. *NOTE* it is assumed that the first 3 columns 
            represent the CoM state
        side (str): "r" or "l", look at right or left step. *NOTE* currently ignored.

    :returns:
        fig (figure handle): a handle of the figure which will be created

    """
    fig = figure(figsize=(17,7))
    
    # identify indices of CoM in kdata_r - data
    cidxr = []
    for req_lbl in ['com_z', 'v_com_x', 'v_com_y']:
        for idx, lbl in enumerate(kdata_r.kin_labels):
            if lbl.lower() == req_lbl.lower():
                cidxr.append(idx)
                break
    cidxr = array(cidxr)
    print "indices of CoM in right submodel data:", cidxr
    
    # identify indices of CoM in kdata_l - data
    cidxl = []
    for req_lbl in ['com_z', 'v_com_x', 'v_com_y']:
        for idx, lbl in enumerate(kdata_l.kin_labels):
            if lbl.lower() == req_lbl.lower():
                cidxl.append(idx)
                break
    cidxl = array(cidxl)
    print "indices of CoM in left submodel data:", cidxl
        
    # make prediction for SLIP parameters
    ax1 = fig.add_subplot(1,4,1)
    pred1 = st.predTest(kdata_r.s_kin_r, kdata_r.s_param_r, rcond=1e-7)
    pred2 = st.predTest(kdata_full.s_kin_r, kdata_r.s_param_r, rcond=1e-7)
    pred3 = st.predTest(hstack([kdata_r.s_param_l[:-1,:], kdata_r.s_kin_r[1:, cidxr]]),
             kdata_r.s_param_r[1:, ], rcond=1e-7) # there is no "data before first right apex"
    
    b11 = ax1.boxplot(pred1, positions = arange(pred1.shape[1]) * .6 + .25)
    mi.recolor(b11,'r')
    b12 = ax1.boxplot(pred2, positions = arange(pred2.shape[1]) * .6 + .25)
    mi.recolor(b12,'k')
    b13 = ax1.boxplot(pred3, positions = arange(pred3.shape[1]) * .6 + .25)
    mi.recolor(b13,'g')
    ax1.set_title('prediction for SLIP parameters\nred: reduced model\nblack: full state information\ngreen: [CoM; last SLIP params]')
    ax1.set_xticks(arange(pred1.shape[1]) * .6 + .25)
    ax1.set_xticklabels(['$k$', '$\\alpha$', '$L_0$', '$\\beta$', '$\\Delta E$'])
    ax1.set_yticks(.1 * arange(12))    
    ax1.plot(ax1.get_xlim(), [1, 1], 'k--')
    ax1.set_ylim(0, 1.15)
        
    # make "self consistency" prediction -> CoM state prediction is part of this        
    ax2 = fig.add_subplot(1,4,2)
    pred1 = st.predTest(kdata_r.s_kin_r, kdata_l.s_kin_l, rcond=1e-7)
    pred2 = st.predTest(kdata_full.s_kin_r, kdata_l.s_kin_l, rcond=1e-7)
    pred3 = st.predTest(hstack([kdata_r.s_param_l[:-1,:], kdata_r.s_kin_r[1:, cidxr]]),
             kdata_l.s_kin_l[1:, cidxl], rcond=1e-7) # there is no "data before first right apex"


    b21 = ax2.boxplot(pred1, positions = arange(pred1.shape[1]) * .6 + .25)
    mi.recolor(b21,'r')
    b23 = ax2.boxplot(pred3, positions = cidxl * .6 + .25)
    mi.recolor(b23,'g')
    b22 = ax2.boxplot(pred2, positions = arange(pred2.shape[1]) * .6 + .25)
    mi.recolor(b22,'k')
    
    ax2.set_title('state prediction after 1 step \n(self-consistency)\nred: reduced model\nblack: full state information\ngreen: [CoM; last SLIP params]')
    ax2.set_xticks(arange(pred2.shape[1]) * .6 + .25)
    ax2.set_xticklabels(kdata_l.kin_labels, rotation='vertical')
    ax2.set_yticks(.1 * arange(12))
    ax2.plot(ax2.get_xlim(), [1, 1], 'k--')
    ax2.set_ylim(0, 1.15)    
            
        
    # make "self consistency" prediction -> CoM state prediction is part of this
    ax3 = fig.add_subplot(1,4,3)
    pred1 = st.predTest(kdata_r.s_kin_r[:-1, :], kdata_r.s_kin_r[1:, :], rcond=1e-7)
    pred2 = st.predTest(kdata_full.s_kin_r[:-1, :], kdata_r.s_kin_r[1:, :], rcond=1e-7)
    pred3 = st.predTest(hstack([kdata_r.s_param_l[:-2,:], kdata_r.s_kin_r[1:-1, cidxr]]),
             kdata_l.s_kin_r[2:, cidxr], rcond=1e-7) # there is no "data before first right apex"

    b31 = ax3.boxplot(pred1, positions = arange(pred1.shape[1]) * .6 + .2)
    mi.recolor(b31,'r')    
    b33 = ax3.boxplot(pred3, positions = cidxr * .6 + .25)
    mi.recolor(b33,'g')
    b32 = ax3.boxplot(pred2, positions = arange(pred2.shape[1]) * .6 + .225)
    mi.recolor(b32,'k')

    ax3.set_title('state prediction after 1 stride\n (self-consistency test)\nred: reduced model\nblack: full state information')
    ax3.set_xticks(arange(pred2.shape[1]) * .6 + .25)
    ax3.set_xticklabels(kdata_r.kin_labels, rotation='vertical')
    ax3.set_yticks(.1 * arange(12))
    ax3.plot(ax3.get_xlim(), [1, 1], 'k--')
    ax3.set_ylim(0, 1.15)

    
    # also: create two-stage prediction model: R->L->R instead of R->->R (directly)
    # first: manually do two-stage prediction     
    # manually do the bootstrap
    # define shortcuts
    dat_r = kdata_r.s_kin_r
    dat_l = kdata_l.s_kin_l
    # 2 stages, reduced model
    bs_vred = []
    for rep in range(100):
        idcs = randint(0, dat_r.shape[0] - 1, dat_r.shape[0] - 1)
        oidx = fda.otheridx(idcs, dat_r.shape[0] - 1)
        # regression R->L
        A = dot(dat_l[idcs, :].T, pinv(dat_r[idcs, :].T, rcond=1e-7))
        # regression L->R
        B = dot(dat_r[idcs + 1, :].T, pinv(dat_l[idcs, :].T, rcond=1e-7))
        pred = None # debug. dot(A, dat_r[oidx, :].T).T
        pred_tot = reduce(dot, [B, A, dat_r[oidx, :].T]).T
        vred = var(dat_r[oidx + 1, :] - pred_tot, axis=0) / var(dat_r[oidx + 1, :], axis=0)
        bs_vred.append(vred)
    bs_mdl = vstack(bs_vred)
    # 2 stages, full model, select only which coordinates to display
    # identify which components (indices) are taken in the small models:
    idx_mdl = []
    for idx in arange(kdata_r.s_kin_r.shape[1]):
        for idxf in arange(kdata_full.s_kin_r.shape[1]):
            if allclose(kdata_full.s_kin_r[:, idxf], kdata_r.s_kin_r[:, idx], atol=1e-7):
                idx_mdl.append(idxf)
                break
    submdl_ident = len(idx_mdl) == kdata_r.s_kin_r.shape[1] # all corresponding dimensions found
    if submdl_ident:
        idx_mdl = array(idx_mdl)
        print "corresponding dimensions of reduced and full model identified"
        print "indices:", idx_mdl
    
        dat_r = kdata_full.s_kin_r
        dat_l = kdata_full.s_kin_l
        bs_vred = []
        for rep in range(100):
            idcs = randint(0, dat_r.shape[0] - 1, dat_r.shape[0] - 1)
            oidx = fda.otheridx(idcs, dat_r.shape[0] - 1)
            # regression R->L
            A = dot(dat_l[idcs, :].T, pinv(dat_r[idcs, :].T, rcond=1e-7))
            # regression L->R
            B = dot(dat_r[idcs + 1, :].T, pinv(dat_l[idcs, :].T, rcond=1e-7))
            pred = None # dot(A, dat_r[oidx, :].T).T
            pred_tot = reduce(dot, [B, A, dat_r[oidx, :].T]).T
            vred = var(dat_r[oidx + 1, :] - pred_tot, axis=0) / var(dat_r[oidx + 1, :], axis=0)
            bs_vred.append(vred)
        bs_full = vstack(bs_vred)
    # 2 stages, augmented SLIP model ( [CoM; last SLIP params] )
    dat_r = hstack([ kdata_r.s_kin_r[1:, cidxr], kdata_r.s_param_l[:-1, :] ])
    dat_l = hstack([ kdata_l.s_kin_l[1:, cidxl], kdata_l.s_param_r[1:, :] ])
    bs_vred = []
    for rep in range(100):
        idcs = randint(0, dat_r.shape[0] - 1, dat_r.shape[0] - 1)
        oidx = fda.otheridx(idcs, dat_r.shape[0] - 1)
        # regression R->L
        A = dot(dat_l[idcs, :].T, pinv(dat_r[idcs, :].T, rcond=1e-7))
        # regression L->R
        B = dot(dat_r[idcs + 1, :].T, pinv(dat_l[idcs, :].T, rcond=1e-7))
        pred = None # debug. remove this line if no error occurs dot(A, dat_r[oidx, :].T).T
        pred_tot = reduce(dot, [B, A, dat_r[oidx, :].T]).T
        vred = var(dat_r[oidx + 1, :] - pred_tot, axis=0) / var(dat_r[oidx + 1, :], axis=0)
        bs_vred.append(vred)
    bs_augslip = vstack(bs_vred)[:, :3]
    # display results
    ax4 = fig.add_subplot(1,4,4)
    b41 = ax4.boxplot(bs_mdl, positions = arange(bs_mdl.shape[1]) * .6 + .25)
    mi.recolor(b41,'r')
    b43 = ax4.boxplot(bs_augslip, positions = cidxr * .6 + .25)
    mi.recolor(b43,'g')
    if submdl_ident:
        b42 = ax4.boxplot(bs_full[:, idx_mdl], positions = arange(len(idx_mdl)) * .6 + .275)
        mi.recolor(b42,'k')
    ax4.set_title('state prediction after 1 stride using\n two steps for prediction\nred: reduced model\nblack: full state information')
    ax4.set_xticks(arange(bs_mdl.shape[1]) * .6 + .25)
    ax4.set_xticklabels(kdata_r.kin_labels, rotation='vertical')
    ax4.set_yticks(.1 * arange(12))
    ax4.plot(ax4.get_xlim(), [1, 1], 'k--')
    ax4.set_ylim(0, 1.15)
        
    
    return fig

Step 3.7.1: 14D: x,y,vx,vy of ankles (8D) + (5D) COM (with one of 6D is identically 0)

step 3: find minimal predictors
step 3.7: test different explicit models
to content

NOTE for the full Floquet model, the prediction quality increases when the number of sections that describe one stride is increased. As expected, this does not hold true for in-sample predictions.


In [333]:
#k3.selection = ['com_x', 'com_y', 'com_z', 'r_anl_y - com_y', 'l_anl_y - com_y', 'r_anl_z - com_z', 'l_anl_z - com_z', ]
#kdata = build_dataset(k3, SlipData)
#fig = test_model(kdata, kdata, kdata_full)

In [337]:
k3.selection = ['com_x', 'com_y', 'com_z', 'r_anl_y - com_y', 'l_anl_y - com_y', 'r_anl_z - com_z', 'l_anl_z - com_z']
kdata = build_dataset(k3, SlipData)
fig = test_model(kdata, kdata, kdata_full)


indices of CoM in right submodel data: [0 5 6]
indices of CoM in left submodel data: [0 5 6]
corresponding dimensions of reduced and full model identified
indices: [ 0  1 11 20 21 23 24 25 35 44 45]

step 3.7.2: model 2 (x,y) both ankles, (vx, vy) swing leg (which swing leg?)

step 3: find minimal predictors
step 3.7: test different explicit models
to content


In [49]:
# variant 1: remove swing leg velocities
k3.selection = ['com_x', 'com_y', 'com_z', 'r_anl_y - com_y', 'r_anl_z - com_z', 'l_anl_y - com_y', 'l_anl_z - com_z']
kdata_r = build_dataset(k3, SlipData)
k3.selection = ['com_x', 'com_y', 'com_z', 'l_anl_y - com_y', 'l_anl_z - com_z', 'r_anl_y - com_y', 'r_anl_z - com_z']
kdata_l = build_dataset(k3, SlipData)
# manually remove velocity of swing leg from data
kdata_r.s_kin_r = kdata_r.s_kin_r[:, :-2]
kdata_r.kin_labels = kdata_r.kin_labels[:-2]

kdata_l.s_kin_l = kdata_l.s_kin_l[:, :-2]
kdata_l.kin_labels = kdata_l.kin_labels[:-2]


fig = test_model(kdata_r, kdata_l, kdata_full)


corresponding dimensions of reduced and full model identified
indices: [ 0  1 20 11 21 22 23 24 43]

In [14]:
# variant 2: remove stance leg velocities
k3.selection = ['com_x', 'com_y', 'com_z', 'l_anl_y - com_y', 'l_anl_z - com_z', 'r_anl_y - com_y', 'r_anl_z - com_z']
kdata_r = build_dataset(k3, SlipData)
k3.selection = ['com_x', 'com_y', 'com_z', 'r_anl_y - com_y', 'r_anl_z - com_z', 'l_anl_y - com_y', 'l_anl_z - com_z']
kdata_l = build_dataset(k3, SlipData)

# manually remove velocity of swing leg from data
kdata_r.s_kin_r = kdata_r.s_kin_r[:, :-2]
kdata_r.kin_labels = kdata_r.kin_labels[:-2]

kdata_l.s_kin_l = kdata_l.s_kin_l[:, :-2]
kdata_l.kin_labels = kdata_l.kin_labels[:-2]


fig = test_model(kdata_r, kdata_l, kdata_full)


corresponding dimensions of reduced and full model identified
indices: [ 0 11 21  1 20 22 23 34 44]

step 3.7.3: model 3 (x,y,vx,vy) of swing ankle only (what is swing? left leg if next touchdown will be right leg?)

step 3: find minimal predictors
step 3.7: test different explicit models
to content


In [51]:
# here: use only information from leg that will touchdown next
k3.selection = ['com_x', 'com_y', 'com_z', 'r_anl_y - com_y', 'r_anl_z - com_z', ]
kdata_r = build_dataset(k3, SlipData)
k3.selection = ['com_x', 'com_y', 'com_z', 'l_anl_y - com_y', 'l_anl_z - com_z', ]
kdata_l = build_dataset(k3, SlipData)

fig = test_model(kdata_r, kdata_l, kdata_full)


corresponding dimensions of reduced and full model identified
indices: [ 0  1 20 22 23 24 43]

include lateral information: state + velocity of upcoming stance leg


In [338]:
# here: use only information from leg that will touchdown next 
k3.selection = ['com_x', 'com_y', 'com_z', 'r_anl_y - com_y', 'r_anl_z - com_z', 'r_anl_x - com_x',] #'r_sia_y - l_sia_y'] # add hip rotation indicator?
kdata_r = build_dataset(k3, SlipData)
k3.selection = ['com_x', 'com_y', 'com_z', 'l_anl_y - com_y', 'l_anl_z - com_z', 'l_anl_x - com_x',] #'r_sia_y - l_sia_y'] # add hip rotation indicator?
kdata_l = build_dataset(k3, SlipData)

fig = test_model(kdata_r, kdata_l, kdata_full)


indices of CoM in right submodel data: [0 4 5]
indices of CoM in left submodel data: [0 4 5]
corresponding dimensions of reduced and full model identified
indices: [ 0  1 20  2 23 24 25 44 26]

In [53]:
# interchange stance leg <-> swing leg
fig = test_model(kdata_l, kdata_r, kdata_full)


corresponding dimensions of reduced and full model identified
indices: [ 0 11 21 12 22 23 34 44 35]

Step 4: Create controlled SLIP (forward simulation)

step 4.1: find periodic solution
step 4.2: compute parameter prediction maps
step 4.3: define stride function
step 4.4: compute jacobian
to content

The closed loop model reads as follows:

Step 1 ("right"):
state = [IC; Factors] where IC = initial CoM state at apex
params = P1 * state where P is a regression from data
new_state = [ode(IC, params); Q1 * [IC; Factors]] where Q is a regressed map from data

Step 2 ("left"):
state = [IC; Factors] where IC = initial CoM state at apex params = P2 * state where P is a regression from data new_state = [ode(IC, params); Q2 * [IC; Factors]] where Q is a regressed map from data

stage 1: find periodic solution

step 4: create controlled SLIP
to content

Approach 1: find periodic solution that corresponds to the average parameters, and verify that it's close to the average initial conditions.
Approach 2: find periodic solution that corresponds to the average initial conditions (and time and ymin), and verify that the corresponding parameters are close to the average parameters

to select approach 1 or 2, go to the "init" block at the top of this notebook


In [57]:
k4 = ws9.k # or any other dataset from build_dataset
po_average_over_IC = True
import models.sliputil as su

mean_pr = mean(vstack(k4.all_param_r), axis=0)
mean_pl = mean(vstack(k4.all_param_l), axis=0) #param_left), axis=0)
mean_ICr = mean(k4.all_IC_r, axis=0)
mean_ICl = mean(k4.all_IC_l, axis=0)
mass = mean(k4.masses)
if not po_average_over_IC: # average parameters, compute corresponding periodic solution
    mean_pl[4] = -mean_pr[4] # set total energy change to exactly zero. 
    # Note: typically, the difference is low, roughly ~0.01 J 
    ICp_r, ICp_l = su.getPeriodicOrbit_p(mean_pr, mean_pl, aug_dict={'m': mass, 'g' : -9.81}, startState=mean_ICr)

else: # average initial conditions, compute corresponding periodic solution
    [ICp_r, Pp_r, dE_r], [ICp_l, Pp_l, dE_l] = su.getPeriodicOrbit(k4.all_IC_r, vstack(k4.TR), vstack(k4.yminR),  
        k4.all_IC_l, vstack(k4.TL), vstack(k4.yminL), baseParams ={'m': mass, 'g' : -9.81}, startParams=mean(vstack(k4.all_param_r), axis=0)[:4])
    
    # change last element to be energy input - this is consistent with the format used in the rest of the code
    Pp_r = array(Pp_r)
    Pp_l = array(Pp_l)
    Pp_r[4] = dE_r
    Pp_r = Pp_r[:5]
    Pp_l[4] = dE_l
    Pp_l = Pp_l[:5]
    
    # rename "periodic parameters" such that they are used in subsequent code cells
    mean_pr = Pp_r
    mean_pl = Pp_l

Sanitycheck of results:

  • check periodicity
  • check deviation of SLIP periodic orbit from mean experimental data

In [60]:
#verify periodicity
sr1 = su.finalState(ICp_r, mean_pr, addDict = {'m' : mass, 'g' : -9.81})
sl1 = su.finalState(ICp_l, mean_pl, addDict = {'m' : mass, 'g' : -9.81})
print "difference between identified periodic orbit and simulation results:"
print sr1 - ICp_l
print sl1 - ICp_r
print '\n===========================================================\n'
print "Deviation from periodic orbit to average apex state, in units of standard deviations:"
print "           [height, horizontal speed, lateral speed]"
print "left step: ", (ICp_l - mean_ICl) / std(k4.all_IC_l, axis=0)
print "right step:", (ICp_r - mean_ICr) / std(k4.all_IC_r, axis=0)

print '\n===========================================================\n'
print "relative deviation from periodic parameters to mean parameters,"
print "in units of standard deviation of parameters"
print "[k, alpha, l0, beta, deltaE]"
print (mean_pr - mean(k4.all_param_r, axis=0)) / std(k4.all_param_r, axis=0)
print (mean_pl - mean(k4.all_param_l, axis=0)) / std(k4.all_param_l, axis=0)


difference between identified periodic orbit and simulation results:
[ -1.47128976e-11  -2.13670883e-07  -2.25007513e-13]
[ -9.89031079e-12  -6.63252183e-07   5.06890176e-10]

===========================================================

Deviation from periodic orbit to average apex state, in units of standard deviations:
           [height, horizontal speed, lateral speed]
left step:  [ 0.  0.  0.]
right step: [ 0.  0.  0.]

===========================================================

relative deviation from periodic parameters to mean parameters,
in units of standard deviation of parameters
[k, alpha, l0, beta, deltaE]
[-0.02022337  0.02428696 -0.04341478 -0.00685831  0.00096452]
[-0.03117478  0.02077271 -0.03481028  0.00654338 -0.0014754 ]

In [65]:
print mean(vstack(k4.IC_right), axis=0) #display()

print k4.all_IC_r.shape
print vstack(k4.IC_right).shape
mean(k4.all_IC_r, axis=0)
#[sx.vBelt for sx in SlipData]


[ 1.00689675  2.87788134  0.04281139]
(1957, 3)
(1959, 3)
Out[65]:
array([ 1.00689746,  2.87786266,  0.04280586])

stage 2: compute parameter prediction maps ("controller") and "factors" prediction

step 4: create controlled SLIP
to content


In [66]:
# new: moved to module
from models.sliputil import getControlMaps

In [93]:
# old code
dt_fstate_r = hstack([fda.dt_movingavg(k4.all_IC_r, 30), fscore_r])
dt_fstate_l = hstack([fda.dt_movingavg(k4.all_IC_l, 30), fscore_l])
dt_fstate_r -= mean(dt_fstate_r, axis=0)
dt_fstate_l -= mean(dt_fstate_l, axis=0)

# compute parameter prediction maps
_, all_ctrl_r, _ = fda.fitData(dt_fstate_r, dt_param_r, nps=1, nrep=200, sections=[0,], rcond=1e-8)
_, all_ctrl_l, _ = fda.fitData(dt_fstate_l, dt_param_l, nps=1, nrep=200, sections=[0,], rcond=1e-8)
ctrl_r = fda.meanMat(all_ctrl_r)
ctrl_l = fda.meanMat(all_ctrl_l)

# compute factors prediction maps - "propagators" of factor's state
_, all_facprop_r, _ = fda.fitData(dt_fstate_r, fscore_l, nps=1, nrep=200, sections=[0,], rcond=1e-8)
_, all_facprop_l, _ = fda.fitData(dt_fstate_l[:-1, :], fscore_r[1:, :], nps=1, nrep=200, sections=[0,], rcond=1e-8)
facprop_r = fda.meanMat(all_facprop_r)
facprop_l = fda.meanMat(all_facprop_l)

stage 3a: define stride function of controlled SLIP

step 4: create controlled SLIP
to content

Note that this function does not depend on the actual shape of the factors, i.e. if there are 3 or 5 factors.

stage 3b: create autonomous system


In [94]:
from models.sliputil import get_auto_sys
allow_nonzero_ref = 1 # set this to zero to force "zero" as reference for the fscores!
#mean_ICl
refstate_r = hstack([ICp_r, allow_nonzero_ref * mean(fscore_r, axis=0)]) # the latter should be zero anyway
refstate_l = hstack([ICp_l, allow_nonzero_ref * mean(fscore_l, axis=0)]) # the latter should be zero anyway

# f is now an autonomous, controlled SLIP stride function

f = get_auto_sys(mean_pr, mean_pl,  refstate_r, refstate_l, ctrl_r, ctrl_l, facprop_r, facprop_l, {'m': mass, 'g':-9.81})

In [95]:
f(refstate_l)


Out[95]:
array([ 1.00584335,  2.88079133,  0.00409522,  0.06264833, -1.66265916,
       -0.11250603])

In [ ]:
# test sensitivity. This is bugfixing prior to computation of Jacobian.
h = .0001
elem = 0
IC = refstate_r.copy()
IC[elem] += h
fsp = f(IC)
IC[elem] -= 2*h
fsn = f(IC)
set_printoptions(precision=4)
print array(fsp - refstate_r) / (2.*h)
print array(fsn - refstate_r) / (2.*h)

stage 4: compute jacobian

step 4: create controlled SLIP
to content
also, visualize eigenvalues and eigenvalues of the "reduced" discrete model


In [97]:
J = []
h = .001
for elem in range(len(refstate_r)):
    IC = refstate_r.copy()
    IC[elem] += h
    fsp = f(IC)
    IC[elem] -= 2*h
    fsn = f(IC)
    J.append((fsp - fsn) / (2.*h))
    
J = vstack(J).T

#visualize

figure()
for ev in eig(J)[0]:
    plot(ev.real, ev.imag, 'rd')
    
axis('equal')

vi_red.vis1()
xlim(-1,1)
ylim(-1,1)
title('eigenvalues of reduced model vs. controlled SLIP model')


---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-97-855ecc140f85> in <module>()
     19 axis('equal')
     20 
---> 21 vi_red.vis1()
     22 xlim(-1,1)
     23 ylim(-1,1)

NameError: name 'vi_red' is not defined

Step 5: Compare Eigenvalues of different models (corresponding return maps)

to content

Here: Also eigenvalues of the full state floquet model


In [ ]:
# compute stride maps from sections maps
# note: the correct order in the product of maps is  map_n * map_(n-1) * ... * map_1
# otherwise, the resulting matrix is not a propagator
# -> reverse ordering of maps
all_maps = [reduce(dot, maps[::-1]) for maps in zip(*maps_pt)]

vi3 = ut.VisEig(127, False)
for A in all_maps:
    vi3.add(eig(A)[0])

figure(figsize=(18, 6))

subplot(1,3,1)

vr = vi_full.vis1()[0]
vr.set_cmap(cm.jet)
vr = vi_red.vis1()[0]
vr.set_cmap(cm.hot)
xlim(-1,1)
ylim(-1,1)
title('eigenvalue distribution "reduced model" (red)\n vs. full model (sections at apex)')


subplot(1,3,2)
vr = vi3.vis1()[0]
vr.set_cmap(cm.jet)
vr = vi_red.vis1()[0]
vr.set_cmap(cm.hot)
xlim(-1,1)
ylim(-1,1)
title('eigenvalues of full kinematic model\nwith %i sections per stride\n vs. reduced model(red)'
  % len(map_sections))
xlabel('real part')
ylabel('imaginary part')



subplot(1,3,3)
vr = vi3.vis1()[0]
vr.set_cmap(cm.jet)
vr = vi_red.vis1()[0]
vr.set_cmap(cm.hot)
for ev in eig(J)[0]:
    plot(ev.real, ev.imag, 'kd')
    
xlim(-1,1)
ylim(-1,1)
title('\n'.join(['eigenvalues of full kinematic model',
'with %i sections per stride', 'vs. reduced model(red)',
      'vs. forward model (diamonds)'])
  % len(map_sections))
xlabel('real part')
ylabel('imaginary part')


draw()

Step 6: Visualize predictors ("factors")

to content


In [ ]:
mag_thresh = .33
#mag_thresh = 0
facs_l_large = array(abs(facs_l) > mag_thresh) * facs_l
facs_r_large = array(abs(facs_r) > mag_thresh) * facs_r

figure(figsize=(15,4))
subplot(2,1,1)
pcolor(facs_l_large.T)
colorbar()
clim(-1,1)
xlim(0,41)
gca().set_yticks(arange(3) + .5)
gca().set_yticklabels([])
gca().set_xticks(arange(41) + .5)
gca().set_xticklabels([])
ylabel('for left leg')
title('elements of factors for predicting SLIP parameters, thresholded')
subplot(2,1,2)
pcolor(facs_r_large.T)
colorbar()
lbls = k.selection[2:] + [('v_' + pt) for pt in k.selection[:2] + k.selection[3:]]
gca().set_xticks(arange(41) + .5)
gca().set_xticklabels(lbls, rotation=90)
gca().set_yticks(arange(3) + .5)
ylabel('for right leg')
gca().set_yticklabels([])
clim(-1,1)
xlim(0,41)

print len(lbls)

TODO's:

  • "rotate" factors such that the same subspace is spanned by them, however minimizing the L1-norm Q: is this still relevant?

    approach would be (idea):

    • build a parametrized rotation matrix
    • calculate the L1-norm as function of the parmeters
    • use gradient descent or some other optimization routine

In [ ]:
# test autonomy of system [IC; factor 2; factor 3]
# test autonomus systems: ankle-SLIP unilateral / bilateral 
# find good reduced EXPLICIT model!

# can we rotate the 5-factor state to COM-state + 2 factors?

Step 7: Testing the autonomy of "[IC; factor2; factor3]" system

to content

Q: how to compute "factor2; factor 3" properly?
A: use projections:

  1. project all basis vectors on (1 - projector_on_IC)
  2. make PCA on vectors
  3. visualize s**2
  4. take only largest components

In [ ]:
# define dimensionality of new model. NOTE: must be <= n_factors


mdl_size = 2
p_IC = dot(IC_sel, IC_sel.T) # projector on IC
p_rem = eye(p_IC.shape[0]) - p_IC # 1 - projector on IC

f_reduced = dot(p_rem, facs_r)
u, s, v = svd(f_reduced, full_matrices=False)
facs_r_noIC = u[:, :mdl_size].copy()

f_reduced = dot(p_rem, facs_l)
u, s, v = svd(f_reduced, full_matrices=False)
facs_l_noIC = u[:, :mdl_size].copy()

# use this to select ankle-SLIP
if select_ankle_SLIP:
    
    nr_dim = 8 # select 4 or 8
    # === HUGE ankle model: +8 states ====
    facs_r_noIC = zeros((41,nr_dim))
    facs_l_noIC = zeros((41,nr_dim))
    # select right ankles
    facs_r_noIC[1,0] = facs_r_noIC[2, 1] = facs_r_noIC[22,2] = facs_r_noIC[23,3] = 1 # right ankle states
    if nr_dim == 8:    
        facs_r_noIC[11,4] = facs_r_noIC[12, 5] = facs_r_noIC[32,6] = facs_r_noIC[33,7] = 1 # left ankle states
    # select left ankles
    facs_l_noIC[11,0] = facs_l_noIC[12, 1] = facs_l_noIC[32,2] = facs_l_noIC[33,3] = 1 # left ankle states
    if nr_dim == 8:
        facs_l_noIC[1,4] = facs_l_noIC[2, 5] = facs_l_noIC[22,6] = facs_l_noIC[23,7] = 1 # right ankle states

# projector onto the subspace of the model
rm_selector_l = hstack([facs_l_noIC, IC_sel])
rm_selector_r = hstack([facs_r_noIC, IC_sel])

# the scores on the "non-IC" states
fscore_r_noIC = dot(facs_r_noIC.T, sdt_kin_r.T).T
fscore_l_noIC = dot(facs_l_noIC.T, sdt_kin_l.T).T

In [ ]:
predict_oos = True  # predict out of sample?
# select reduced models as a real subset of the full kinematic state at apex
   
reddat_r = dot(rm_selector_r.T, sdt_kin_r.T).T
reddat_l = dot(rm_selector_l.T, sdt_kin_l.T).T

#p2D_r = p2D_r - mean(p2D_r, axis=0)
#sdt_kin_r = sdt_kin_r - mean(sdt_kin_r, axis=0)

res1 = st.predTest(reddat_r, p2D_r, out_of_sample=predict_oos, rcond=1e-7)
res2 = st.predTest(sdt_kin_r, p2D_r, out_of_sample=predict_oos, rcond=1e-7)

res3 = st.predTest(reddat_l, p2D_l,  out_of_sample=predict_oos, rcond=1e-7)
res4 = st.predTest(sdt_kin_l, p2D_l, out_of_sample=predict_oos, rcond=1e-7)

figure(figsize=(12,6))
subplot(1,2,1)
b1 = boxplot(res1)
b2 = boxplot(res2)
mi.recolor(b1, 'g')
mi.recolor(b2, 'k')
xticks(arange(5) + 1)
gca().set_xticklabels(['k', r'$\alpha$', r'L$_0$', r'$\beta$', r'$\delta$E'], fontsize=16)
xlabel('predicted variable')
ylabel('relative remaining variance')
ylim(0, 1.05)
title('right step SLIP params\nred: reduced model,\nblack: full kinematic state')
subplot(1,2,2)
b1 = boxplot(res3)
b2 = boxplot(res4)
mi.recolor(b1, 'g')
mi.recolor(b2, 'k')
xticks(arange(5) + 1)
gca().set_xticklabels(['k', r'$\alpha$', r'L$_0$', r'$\beta$', r'$\delta$E'], fontsize=16)
xlabel('predicted variable')
ylabel('relative remaining variance')
ylim(0, 1.05)
title('left step SLIP params\nred: reduced model,\nblack: full kinematic state')

draw()

In [ ]:
# test self-consistency

oos_pred = True # out of sample prediction?

# predict
res1 = st.predTest(reddat_r, reddat_l, out_of_sample=oos_pred, rcond=1e-7)
res2 = st.predTest(sdt_kin_r, reddat_l, out_of_sample=oos_pred, rcond=1e-7)

res3 = st.predTest(reddat_l[:-1, :], reddat_r[1:, :], out_of_sample=oos_pred, rcond=1e-7)
res4 = st.predTest(sdt_kin_l[:-1, :], reddat_r[1:, :], out_of_sample=oos_pred, rcond=1e-7)


figure(figsize=(16,8))
subplot(1,2,1)
b1 = boxplot(res1)
b2 = boxplot(res2)
mi.recolor(b1, 'g')
mi.recolor(b2, 'k')
ylim(0, 1.05)
xticks(arange(res3.shape[1]) + 1)
gca().set_xticklabels(['factor ' + str(nr + 1) for nr in arange(res1.shape[1] - 3)] +
      ['height', 'horiz. speed', 'lat. speed'], rotation=45)
title('predicting left apex state\nred: reduced model, black: full model')
ylabel('relative remaining variance')

subplot(1,2,2)
b1 = boxplot(res3)
b2 = boxplot(res4)
mi.recolor(b1, 'g')
mi.recolor(b2, 'k')
ylim(0, 1.05)
xticks(arange(res3.shape[1]) + 1)
gca().set_xticklabels(['factor ' + str(nr + 1) for nr in arange(res1.shape[1] - 3)] +
      ['height', 'horiz. speed', 'lat. speed'], rotation=45)
title('predicting left apex state\nred: reduced model, black: full model')
ylabel('relative remaining variance')

draw()

Step 8: create correspondingly controlled autonomous SLIP model

Step 8.1: visualize eigenvalues of different models
to content


In [ ]:
# compute propagator matrices

# introduce scaling such that "scores" and "IC" variance is in the same order of magnitude
score_scaling = .04

# first: initialize data
dt_fstate_r_noIC = hstack([fda.dt_movingavg(all_IC_r, 30), fscore_r_noIC * score_scaling])
dt_fstate_l_noIC = hstack([fda.dt_movingavg(all_IC_l, 30), fscore_l_noIC * score_scaling])
dt_fstate_r_noIC -= mean(dt_fstate_r_noIC, axis=0)
dt_fstate_l_noIC -= mean(dt_fstate_l_noIC, axis=0)

#dt_fstate_l_noIC *= .04
#dt_fstate_r_noIC *= .04

# compute parameter prediction maps
_, all_ctrl_r_noIC, _ = fda.fitData(dt_fstate_r_noIC, dt_param_r, nps=1, nrep=200, sections=[0,], rcond=1e-8)
_, all_ctrl_l_noIC, _ = fda.fitData(dt_fstate_l_noIC, dt_param_l, nps=1, nrep=200, sections=[0,], rcond=1e-8)
ctrl_r_noIC = fda.meanMat(all_ctrl_r_noIC)
ctrl_l_noIC = fda.meanMat(all_ctrl_l_noIC)

# compute factors prediction maps - "propagators" of factor's state
#_, all_facprop_r_noIC, _ = fda.fitData(dt_fstate_r_noIC, fscore_l_noIC, nps=1, nrep=200, sections=[0,], rcond=1e-8)
#_, all_facprop_l_noIC, _ = fda.fitData(dt_fstate_l_noIC[:-1, :], fscore_r_noIC[1:, :], nps=1, nrep=200, sections=[0,], rcond=1e-8)
_, all_facprop_r_noIC, _ = fda.fitData(dt_fstate_r_noIC, score_scaling * fscore_l_noIC, nps=1, nrep=200, sections=[0,], rcond=1e-8)
_, all_facprop_l_noIC, _ = fda.fitData(dt_fstate_l_noIC[:-1, :], score_scaling * fscore_r_noIC[1:, :], nps=1, nrep=200, sections=[0,], rcond=1e-8)

facprop_r_noIC = fda.meanMat(all_facprop_r_noIC)
facprop_l_noIC = fda.meanMat(all_facprop_l_noIC)

In [ ]:
from models.sliputil import get_auto_sys
allow_nonzero_ref = 0 # set this to zero to force "zero" as reference for the fscores!
#mean_ICl
refstate_r_noIC = hstack([ICp_r, allow_nonzero_ref * mean(fscore_r_noIC, axis=0)]) # the latter should be zero anyway
refstate_l_noIC = hstack([ICp_l, allow_nonzero_ref * mean(fscore_l_noIC, axis=0)]) # the latter should be zero anyway
    
f_noIC = get_auto_sys(mean_pr, mean_pl,  refstate_r_noIC, refstate_l_noIC, ctrl_r_noIC, ctrl_l_noIC, facprop_r_noIC, facprop_l_noIC, {'m': mass, 'g':-9.81})
#IC = refstate_r             
             
J_noIC = []
h = .001
#h = .001
for elem in range(len(refstate_r_noIC)):
    IC = refstate_r_noIC.copy()
    IC[elem] += h
    fsp = f_noIC(IC)
    IC[elem] -= 2*h
    fsn = f_noIC(IC)
    J_noIC.append((fsp - fsn) / (2.*h))
    
J_noIC = vstack(J_noIC).T

visualize factors


In [ ]:
mag_thresh = .1
#mag_thresh = 0
facs_l_large = array(abs(facs_l_noIC) > mag_thresh) * facs_l_noIC
facs_r_large = array(abs(facs_r_noIC) > mag_thresh) * facs_r_noIC

figure(figsize=(15,3))
subplot(2,1,1)
pcolor(facs_l_large.T)
colorbar()
clim(-1,1)
xlim(0,41)
gca().set_yticks(arange(facs_r_noIC.shape[1]) + .5)
gca().set_yticklabels([])
gca().set_xticks(arange(41) + .5)
gca().set_xticklabels([])
ylabel('for left leg')
title('elements of factors for predicting SLIP parameters, thresholded')
subplot(2,1,2)
pcolor(facs_r_large.T)
colorbar()
lbls = k.selection[2:] + [('v_' + pt) for pt in k.selection[:2] + k.selection[3:]]
gca().set_xticks(arange(41) + .5)
gca().set_xticklabels(lbls, rotation=90)
gca().set_yticks(arange(facs_r_noIC.shape[1]) + .5)
ylabel('for right leg')
gca().set_yticklabels([])
clim(-1,1)
xlim(0,41)

Step 8.1: visualize eigenvalues of different models

Step 8: Create autonomous SLIP with factors
to content


In [ ]:
# compute stride maps from sections maps
# note: the correct order in the product of maps is  map_n * map_(n-1) * ... * map_1
# otherwise, the resulting matrix is not a propagator
# -> reverse ordering of maps
all_maps = [reduce(dot, maps[::-1]) for maps in zip(*maps_pt)]

vi3 = ut.VisEig(127, False)
for A in all_maps:
    vi3.add(eig(A)[0])

figure(figsize=(18, 6))

subplot(1,3,1)

vr = vi_full.vis1()[0]
vr.set_cmap(cm.jet)
vr = vi_red.vis1()[0]
vr.set_cmap(cm.hot)
xlim(-1,1)
ylim(-1,1)
title('eigenvalue distribution "reduced model" (red)\n vs. full model (sections at apex)')


subplot(1,3,2)
vr = vi3.vis1()[0]
vr.set_cmap(cm.jet)
vr = vi_red.vis1()[0]
vr.set_cmap(cm.hot)
xlim(-1,1)
ylim(-1,1)
title('eigenvalues of full kinematic model\nwith %i sections per stride\n vs. reduced model(red)'
  % len(map_sections))
xlabel('real part')
ylabel('imaginary part')



subplot(1,3,3)
vr = vi3.vis1()[0]
vr.set_cmap(cm.gray)
vr = vi_red.vis1()[0]
vr.set_cmap(cm.hot)
for ev in eig(J)[0]:
    plot(ev.real, ev.imag, 'kd', markersize=9)
    
for ev in eig(J_noIC)[0]:
    plot(ev.real, ev.imag, 'v', color='#24ff49', markersize=7.5)
    
xlim(-1,1)
ylim(-1,1)
if select_ankle_SLIP:
    last_mdl = ' ankle-SLIP '
else:
    last_mdl =  '"no-IC-factors" forward model '
title('\n'.join(['eigenvalues of full kinematic model (gray)',
'with %i sections per stride', 'vs. reduced model(red)',
      'vs. forward model (black diamonds)',
  'vs. ' + last_mdl + ' (green triangles)'])
  % len(map_sections))
xlabel('real part')
ylabel('imaginary part')


draw()

In [ ]:
# compute 5 factors
# let's assume that the first 3 components are CoM states
# use Gram-Schmidt to make first three cols "unity matrix" (5x3)
# (use Gram-Schmidt to) minimize the L2-norm of the upper right 3x38-factor matrix

# alternatively:
# start with 3x3 - identity (+ 3x38)
# add two [0 0 0, 38x] vectors to minimize the prediction error in parameters (explicit formula? iterative?)

# alternatively: re-work my original SVD approach

In [ ]:
ev, ew = eig(J_noIC)
figure('EV dist', figsize=(16,6))
subplot(1,2,1)
plot(abs(ev), 'rd')
xlabel('ordinal of eigenvalue')
ylabel('magnitude of eigenvalue')
subplot(1,2,2)
pcolor(abs(ew[::-1,:]))
gca().set_xticks((arange(ew.shape[0]) + .5))
gca().set_xticklabels((arange(ew.shape[0]) + 1))
gca().set_yticks((arange(ew.shape[0]) + .5))
gca().set_yticklabels((arange(ew.shape[0]) + 1))
xlim(0,ew.shape[0])
ylim(ew.shape[0], 0)
clim(0,1)
colorbar()
title('magnitude of eigenvector matrix')
xlabel('ordinal of eigenvector')
ylabel('coordinate [1-3: CoM]')

In [ ]:
figure()
pcolor(
    vstack([abs(ew[:,col]) / std(dt_fstate_r_noIC, axis=0) for col in arange(ew.shape[1])]).T
    )
colorbar()
title('"scaled" eigenvector matix')

Step 9: Comparison of trajectory prediction: controlled SLIP vs. full Floquet model vs. reduced model vs. uncontrolled (fixed parameter) SLIP

Step 9.1: Select and prepare data
Step 9.2: create bootstrapped Floquet models
Step 9.3: test continous prediction for Floquet models
Step 9.4: (now obsolete)
Step 9.5: compute Phase for SLIP
Step 9.6: perform predictions
to content

Approch:

to compare:

  • CoM (x|y|z)

  • for continuous data with phase:

    • build full state maps that map to apex NEW: start directly with apex data
    • build maps that map from apex to phase [0 ... pi]
    • build map that map from apex to next apex
    • build continous prediction models using this data as input
  • for discrete data at apex:
    • build continuous prediction model
    • Assume that phase goes from 0 to pi linearly (from apex to apex)?
  • for SLIP simulation:
    • run model
    • Assume that phase goes from 0 to pi linearly (from apex to apex)?

Approach:

  1. prepare data
  2. build forward (Floquet-) models: full and reduced
  3. build controlled SLIP model

In [1]:
import mutils.io as mio
import mutils.misc as mi
import mutils.FDatAn as fda

from copy import deepcopy

from mutils.io import build_dataset
from models.sliputil import get_auto_sys, getControlMaps


ws9 = mio.saveable()

k9 = mio.KinData()
ws9.subject = 2
ws9.ttype = 1
k9.load(ws9.subject, ws9.ttype) # subject in [1,2,3,7], ttype=1

SlipData = [mi.Struct(mio.mload('../data/2013-newSlip/SLIP_s%it%ir%i.dict' % (ws9.subject, ws9.ttype, rep)))
           for rep in k9.reps]

k9.selection = ['com_x', 'com_y', 'com_z', 'r_anl_y - com_y', 'r_anl_z - com_z', 'r_anl_x - com_x']
ws9.dataset_r = build_dataset(k9, SlipData)
k9.selection = ['com_x', 'com_y', 'com_z', 'l_anl_y - com_y', 'l_anl_z - com_z', 'l_anl_x - com_x']
ws9.dataset_l = build_dataset(k9, SlipData)




ws9.stride_idcs = [1200, 1201, 1202, 1203] # numbers of strides to predict

ws9.k9 = mio.KinData()
ws9.k9.load(ws9.subject, ws9.ttype) # subject in [1,2,3,7], ttype=1
ws9.k9.selection = [ 'com_x', 'com_y', 'com_z',
             'r_anl_y - com_y', 'r_anl_x - com_x', 'r_mtv_z - r_anl_z', 'r_mtv_x - r_anl_x', 'r_kne_y - com_y',
             'r_elb_y - com_y', 'r_elb_x - com_x', 'r_wrl_z - com_z', 'r_wrl_x - com_x', 'cvii_y - com_y',
             'l_anl_y - com_y', 'l_anl_x - com_x', 'l_mtv_z - l_anl_z', 'l_mtv_x - l_anl_x', 'l_kne_y - com_y',
             'l_elb_y - com_y', 'l_elb_x - com_x', 'l_wrl_z - com_z', 'l_wrl_x - com_x', 
             'r_anl_z - com_z', 'l_anl_z - com_z']

ws9.SlipData = [mi.Struct(mio.mload('../data/2013-newSlip/SLIP_s%it%ir%i.dict' % (ws9.subject, ws9.ttype, rep)))
           for rep in ws9.k9.reps]
ws9.kdata_full = build_dataset(ws9.k9, ws9.SlipData)
ws9.k = ws9.kdata_full

compute average phase at left and right apex

sanity check: are apex times approximately at the same phase (mod 2 pi)?


In [2]:
ws9.a_phi_apex_r = mod(hstack([mi.upper_phases(d.phases[:-1], sep=0) for d in ws9.SlipData]), 2*pi)
ws9.a_phi_apex_l = mod(hstack([mi.upper_phases(d.phases[:-1], sep=pi) for d in ws9.SlipData]), 2*pi)
ws9.phi_apex_r = mean(ws9.a_phi_apex_r)
ws9.phi_apex_l = mean(ws9.a_phi_apex_l)
ws9.s_phi_apex_r = std(ws9.a_phi_apex_r)
ws9.s_phi_apex_l = std(ws9.a_phi_apex_l)
figure(figsize=(6,4))
hist(ws9.a_phi_apex_r)
xlabel('phases of "right apex" events')
ylabel('appearances')
print "apex right at phase: ", ws9.phi_apex_r, ' +- ', ws9.s_phi_apex_r
print "apex left  at phase: ", ws9.phi_apex_l, ' +- ', ws9.s_phi_apex_l
print "difference [in units of pi]:", (ws9.phi_apex_l - ws9.phi_apex_r) / pi


apex right at phase:  0.968171141508  +-  0.0570463653195
apex left  at phase:  4.19139188514  +-  0.0637191342536
difference [in units of pi]: 1.02598302805

step 9.2: create bootstrapped Floquet models

step 9: compare trajectories SLIP vs. Floquet models
to content


In [3]:
# prepare data
# get kinematics at different phases - interpolate using k.i_phases
ws9.nps = 50

#the final [:, nps*2:] removes the com position in horizontal plane
ws9.d1d_r = ws9.k9.make_1D(nps=ws9.nps, phases_list=ws9.k.all_phases_r)[:, ws9.nps*2:] # starts at "right" apex
ws9.phases_d1d_r = deepcopy(ws9.k9.i_phases)
ws9.d1d_l = ws9.k9.make_1D(nps=ws9.nps, phases_list=ws9.k.all_phases_l)[:, ws9.nps*2:] # starts at "left" apex
ws9.phases_d1d_l = deepcopy(ws9.k9.i_phases)



detrend = lambda x: fda.dt_movingavg(x, 30)

ws9.d1d_r_dt = detrend(ws9.d1d_r)
ws9.d1d_r_trend = ws9.d1d_r - ws9.d1d_r_dt #required for offset ("lift to limit cycle")

ws9.d1d_l_dt = detrend(ws9.d1d_l)
ws9.d1d_l_trend = ws9.d1d_l - ws9.d1d_l_dt # required for offset ("lift to limit cycle")

# create Floquet models, bootstrap them
ws9.n_sct = ws9.nps // 2  # each floquet model is only 25 sections "long" - nps / 2

ws9.fmodels_r = []
print "computing Floquet models for", ws9.n_sct, "sections... (right)"
print "=" * ws9.n_sct
for sec in arange(ws9.n_sct) + 1: # from section 1 to "next apex - 1"
    _, maps_sect, _ = fda.fitData( ws9.d1d_r_dt[:, 0::ws9.nps], ws9.d1d_r_dt[:, sec::ws9.nps],
           sections=[0,], nps=1, rcond=1e-7, nrep=50)
    ws9.fmodels_r.append(fda.meanMat(maps_sect))
    sys.stdout.write('.')

print " done"

ws9.fmodels_l = []
print "computing Floquet models for", ws9.n_sct, "sections... (left)"
print "=" * ws9.n_sct
for sec in arange(ws9.n_sct) + 1: # from section 1 to "next apex - 1"
    _, maps_sect, _ = fda.fitData( ws9.d1d_l_dt[:, 0::ws9.nps], ws9.d1d_l_dt[:, sec::ws9.nps], 
            sections=[0,], nps=1, rcond=1e-7, nrep=50)
    ws9.fmodels_l.append(fda.meanMat(maps_sect))
    sys.stdout.write('.')

print " done"

# compute indices which select only the CoM state: [com_z, v_y, v_z, v_x] ("height, horizontal speed, vert. speed, lat. speed")
ls = len(ws9.k9.selection)
ws9.FM_CoM_sel_idx = array([0, ls-1, ls, ls-2])


computing Floquet models for 25 sections... (right)
=========================
......................... done
computing Floquet models for 25 sections... (left)
=========================
......................... done

step 9.3: test continous prediction for Floquet models

step 9: compare trajectories SLIP vs. Floquet models
to content


In [4]:
# test prediction
rvar = []
for nr, fm in enumerate(ws9.fmodels_r[:-1]):
    pred = dot(fm, ws9.d1d_r_dt[:, 0::ws9.nps].T).T #all_kin_r.T).T
    meas = ws9.d1d_r_dt[:, nr+1:: ws9.nps]
    rvar.append(var(meas - pred, axis=0) / var(meas, axis=0))

    
figure(figsize(16,8))
phase_ticks = linspace(1./len(ws9.fmodels_r), 1, len(ws9.fmodels_r))
pcolor(arange(len(rvar[0])+1), phase_ticks, vstack(rvar))
xlabel('coordinate #')
ylabel('phase to predict (in $\pi$)')
gca().set_xticks(arange(len(ws9.k.kin_labels)+1) + .5)
gca().set_xticklabels(ws9.k.kin_labels, rotation=90)
colorbar()
title('relative remaining variance after prediction (single step!!)')
clim(0,1)


Step 9.4 Continue here: compute continuous predictions using SLIP / reduced models [OBSOLETE]

step 9: compare trajectories SLIP vs. Floquet models
to content

(THIS BLOCK IS OBSOLETE)

Step 9.5 Compute Phase for SLIP model

step 9: compare trajectories SLIP vs. Floquet models
to content

Idea:

  • run (controlled) SLIP until it reaches convergence. This should be after ~20 strides within the desired accuracy (here)
  • run reference SLIP (same controller, but with reference initial conditions), same number of strides
  • define phase of reference SLIP: [0, 2pi] ($\leftarrow$ inclusive!) linearly from apex to apex ($\leftarrow$ inclusive)
  • compute difference in timing betwenn reference and (originally) disturbed SLIP last apex (after 20 strides), say $\delta T$, and set in relation with stride time of unperturbed SLIP $T$
  • Phase difference is now $2\pi \frac{\delta T}{T}$
  • This phase difference is the constant offset of the phase between undisturbed SLIP and singularly perturbed SLIP (this implies that phase progresses at constant speed at the disturbed model!)

TODO:

  • approach: run section 4 to define models. Extend section 4 to (be able to easily) obtain differently controlled SLIPs Q: Is phase defined for an unstable system?

In [5]:
def reord_idx(labels):
    """
    returns indices for re-ordering dataset data such that first three columns are CoM state (SLIP state) 

    :args:
        labels [list]: a list of labels that describe the ordering of the columns. it is scanned for
        com_z (-> idx0) , v_com_x (-> idx2), v_com_y (idx1)

    :returns:
        idcs (array): an array of the size of labels that starts with [idx0, idx1, idx2] and
            contains all numbers from 0 to len(labels)-1.
            This can be used for indexing as follows:

                re_ordered_data = original_data[:, reord_idx(kin_labels)]

    """
    idx0 = [idx for idx, val in enumerate(labels) if val.lower() == 'com_z'][0]
    idx1 = [idx for idx, val in enumerate(labels) if val.lower() == 'v_com_y'][0]
    idx2 = [idx for idx, val in enumerate(labels) if val.lower() == 'v_com_x'][0]
    ridx = list(set(range(len(labels))) - set([idx0, idx1, idx2]))
    idcs = hstack([idx0, idx1, idx2, ridx])
    return idcs

#re-order: CoM at first
states_r = ws9.dataset_r.all_kin_r[:, reord_idx(ws9.dataset_r.kin_labels)]
states_l = ws9.dataset_l.all_kin_l[:, reord_idx(ws9.dataset_l.kin_labels)]

# note: here, implicitly a periodic orbit is computed (given in the reference states)
cmaps, nmaps, refs = getControlMaps(states_r, states_l, ws9.dataset_r)

ws9.ref_state_r, ws9.ref_state_l, ws9.ref_param_r, ws9.ref_param_l, ws9.ref_addDict = refs
ws9.ctrl_r, ws9.ctrl_l = cmaps
ws9.nmap_r, ws9.nmap_l = nmaps

ws9.ref_state_r = hstack([ws9.ref_state_r, (len(ws9.dataset_r.kin_labels) - 3) * [0, ]])
ws9.ref_state_l = hstack([ws9.ref_state_l, (len(ws9.dataset_l.kin_labels) - 3) * [0, ]])

# create autonomous system and check periodicity
cSLIP = get_auto_sys(ws9.ref_param_r, ws9.ref_param_l, ws9.ref_state_r, ws9.ref_state_l, ws9.ctrl_r, ws9.ctrl_l, ws9.nmap_r, ws9.nmap_l, ws9.ref_addDict)
print "periodicity test:"
print cSLIP(ws9.ref_state_r) - ws9.ref_state_r


periodicity test:
[ -4.73139283e-09  -8.24684452e-07   6.34579909e-09  -1.88226102e-11
   3.61542555e-09   4.65475224e-11  -4.52819782e-07   1.39839849e-08
   9.36368087e-09]

In [5]:

compute phase of disturbed stable autonomous system:

Q: How to define and compute the phase for an unstable running SLIP?
A: Although Phase is not properly defined, use Phaser


In [6]:
# requirement: dist_state
dist_state = ws9.ref_state_r.copy() * 1.1

cSLIP_f = get_auto_sys(ws9.ref_param_r, ws9.ref_param_l, ws9.ref_state_r, ws9.ref_state_l,
     ws9.ctrl_r, ws9.ctrl_l, ws9.nmap_r, ws9.nmap_l, ws9.ref_addDict, full_info=True)
# define how many step to run until convergence is reached

nstride = 10

fs_f, (sim_t_ref, sim_states_ref) = cSLIP_f(ws9.ref_state_r)
sim_t_d = [] 
sim_s_d = []
fs_d = dist_state
for rep in range(nstride):
    fs_d, (sim_t, sim_states) = cSLIP_f(fs_d)
    oldtime = 0
    if len(sim_t_d) > 0:
        oldtime = sim_t_d[-1][-1]
    sim_t_d.append(sim_t[:-1] + oldtime)
    sim_s_d.append(sim_states[:-1,:])

sim_s_d.append(sim_states[-1, :][newaxis, :])
sim_t_d.append(sim_t[-1] + oldtime)

sim_s_d = vstack(sim_s_d)
sim_t_d = hstack(sim_t_d)
# now, compute phase (after simulation is completed)

# at the end, phase is 0 (or 2pi) 
# total amount of phase elaped is: (time / sim_t_ref) * 2pi
phi_total = sim_t_d[-1] / sim_t_ref[-1] * (2*pi)
# final phase is: nstride * 2pi
final_phase = nstride * 2*pi
initial_phase = final_phase - phi_total
# disturbed phase is no:
sim_phi_d = sim_t_d /sim_t_ref[-1] * 2*pi + initial_phase
print "phi0:", initial_phase

def getPhase(state, system, nstride=10):
    """
    computes the phase of the given SLIP system at the state "state".

    :args:
        state [n-by-1 array]: the initial state of the system
        system [autonomous SLIP]: the dynamical system (SLIP model), obtained e.g. by models.slip.get_auto_sys
            *NOTE* the system must be stable!
        nstride [int]: number of strides to be simulated before convergence is assumed
        
    :returns:
        (phi0, T) [float, float]: the phase correspoding to the initial condition and the average cycle duration
    """

    # run #nstride strides
    sim_t_d = [] 
    sim_s_d = []
    
    fs_d = array(state).copy()
    for rep in range(nstride):
        fs_d, (sim_t, sim_states) = cSLIP_f(fs_d)
        oldtime = 0
        if len(sim_t_d) > 0:
            oldtime = sim_t_d[-1][-1]
        sim_t_d.append(sim_t[:-1] + oldtime)
        sim_s_d.append(sim_states[:-1,:])
    
    sim_s_d.append(sim_states[-1, :][newaxis, :])
    sim_t_d.append(sim_t[-1] + oldtime)
    
    sim_s_d = vstack(sim_s_d)
    sim_t_d = hstack(sim_t_d)
    
    # assume that solution is now periodic -> simulate "reference" stride
    fs_f, (sim_t_ref, sim_states_ref) = system(fs_d)
    
    # now, compute phase (after simulation is completed)
    
    # at the end, phase is 0 (or 2pi) 
    # total amount of phase elaped is: (time / sim_t_ref) * 2pi
    phi_total = sim_t_d[-1] / sim_t_ref[-1] * (2*pi)
    # final phase is: nstride * 2pi
    final_phase = nstride * 2*pi
    initial_phase = final_phase - phi_total
    # disturbed phase is no:
    return initial_phase, sim_t_ref[-1]
    
print "from function:", getPhase(dist_state, cSLIP_f)


phi0: -0.0352859088741
from function: (-0.035287415387323051, 0.7336220599471579)

In [7]:
# create system
cSLIP_f = get_auto_sys(ws9.ref_param_r, ws9.ref_param_l, ws9.ref_state_r, ws9.ref_state_l, ws9.ctrl_r, 
ws9.ctrl_l, ws9.nmap_r, ws9.nmap_l, ws9.ref_addDict, full_info=True)
# run reference motion
fs_f, (sim_t, sim_states) = cSLIP_f(ws9.ref_state_r)
figure(figsize=(8,6))
plot(sim_t, sim_states[:,1],'r')
plot(sim_t, sim_states[:,3],'r--')
# run disturbed motion
dist_state_r = ws9.ref_state_r.copy()
dist_state_r[0] += .05 # increase apex height by 5cm
dist_state_r[1] += .15 # increase velocity by .15 m/s
fs_f, (sim_t_d, sim_states_d) = cSLIP_f(dist_state_r)
plot(sim_t_d, sim_states_d[:,1],'g')
plot(sim_t_d, sim_states_d[:,3],'g--')


Out[7]:
[<matplotlib.lines.Line2D at 0x6303790>]

Step 9.6: perform predictions of CoM

step 9: compare trajectories SLIP vs. Floquet models
to content

Approach:

desired output:

A figure that displays the predicted CoM and measured CoM as function of phase.
"Predict from phase 0 to pi"

General preparations

  • select steps to predict [OK -> 9.1]
  • for both sides, left and right, do:

    • compute average phase of right and left apex (which are not necessarily $\pi$ apart) $\to$ ws9.phi_apex_r, ws9.s_phi_apex_l [OK -> 9.1]
    • select desired output phases for both Floquet model and SLIP model(s) [OK]
    • create Floquet models which start at first selected phase after apex $\phi_a \to$ all other phases (Note: there will be an individual "first" map for each selected apex) [OK -> 9.2]
  • create Phaser for uncontrolled SLIP

For the Floquet models:

for each apex do:

  • obtain phase of apex $\phi_a$
  • obtain mapping from state$(\phi_a) \to $ state$(\phi_1)$

For the controlled SLIP models:

  • create controlled model
  • obtain corresponding IC's
  • simulate step
  • compute phase

For the uncontrolled SLIP:

  • create model
  • obtain corresponding IC's
  • simulate step
  • compute phase using phaser

In [8]:
# fixme: change this to the fixed phases! These are: [0 ... 2pi) / nps
fixed_phases = linspace(0, 2*pi, ws9.nps, endpoint=False)
pred_phases = roll(fixed_phases, -1)
pred_phases[-1] = 2*pi # change 0 -> 2pi
phi_out_r = pred_phases[:25] + ws9.phi_apex_r
phi_out_l = pred_phases[:25] + ws9.phi_apex_l
#fixed_phases = linspace(0, 2*pi, ws9.nps, endpoint=False)

compute mapping apex -> phases[1]

(phase[0] is roughly around apex - might be even before apex.)


In [9]:
# find first index after
step = 1100
phi_apex = mod(ws9.a_phi_apex_r[step], 2*pi) 

#idx_ar = argmin(abs(fixed_phases - ws9.phi_apex_r))
#if fixed_phases[idx_ar] - ws9.phi_apex_r <= 0:    
#    idx_ar += 1
#idx_al = argmin(abs(fixed_phases - ws9.phi_apex_l))
#if fixed_phases[idx_al] - ws9.phi_apex_l <= 0:
#    idx_al += 1
#    
#phi_firstAfter_r = fixed_phases[idx_ar]
#phi_firstAfter_l = fixed_phases[idx_al]
    
# compute mappings from phase state to "first state after apex"
kins = ws9.k9.get_kin()
phases = [x['phi2'] for x in ws9.k9.raw_dat]

im_r = []
if True:
    lidat = []
    lodat = []
    for kin, phi, iphi in zip(kins, phases, ws9.phases_d1d_r):        
        phi_start = iphi[1]
        phi_end = iphi[-ws9.nps + 1] + 2.*pi
        #phi_end = iphi[-1]
        phi_odat = linspace(phi_start, phi_end, len(iphi) / ws9.nps , endpoint=False)
        phi_idat = phi_odat - (phi_start - phi_apex) # fixed_phases[idx_ar] + ws9.phi_apex_r
        # interpolate data according to phi_req (exclude position in horizontal plane)
        idat_raw = vstack([interp(phi_idat, phi.squeeze(), kin[row, :]) for row in range(2, kin.shape[0])])
        lidat.append(idat_raw)
        odat_raw = vstack([interp(phi_odat, phi.squeeze(), kin[row, :]) for row in range(2, kin.shape[0])])
        lodat.append(odat_raw)
        #odat.append(vstack([fda.dt_movingavg(interp(phi_odat, phi.squeeze(), kin[row,:]), 30) for row in range(2, kin.shape[0])]))
        #something like odat = interp(phi_odat, phi_raw, kin_coord)

    idat = fda.dt_movingavg(hstack(lidat).T, 30)
    odat = fda.dt_movingavg(hstack(lodat).T, 30)
    print "bootstrapping..."
    print "=" * 50
    for rep in range(50):
        sel_idx = randint(0, idat.shape[0], idat.shape[0])
        init_mapping_r = dot(pinv(idat[sel_idx, :], rcond=1e-8), odat[sel_idx, :]).T
        im_r.append(init_mapping_r)
        sys.stdout.write('.')
    print "done"

im_r_m = fda.meanMat(im_r)


lidat = []
lodat = []
for kin, phi, iphi in zip(kins, phases, ws9.phases_d1d_r):
    phi_start = iphi[1]
    phi_end = iphi[-ws9.nps + 1] + 2.*pi
    #phi_end = iphi[-1]
    phi_odat = linspace(phi_start, phi_end, len(iphi) / ws9.nps , endpoint=False)
    phi_idat = phi_odat - (phi_start - phi_apex) # fixed_phases[idx_ar] + ws9.phi_apex_r
    # interpolate data according to phi_req (exclude position in horizontal plane)
    idat_raw = vstack([interp(phi_idat, phi.squeeze(), kin[row, :]) for row in range(2, kin.shape[0])])
    lidat.append(idat_raw)
    odat_raw = vstack([interp(phi_odat, phi.squeeze(), kin[row, :]) for row in range(2, kin.shape[0])])
    lodat.append(odat_raw)
    #odat.append(vstack([fda.dt_movingavg(interp(phi_odat, phi.squeeze(), kin[row,:]), 30) for row in range(2, kin.shape[0])]))
    #something like odat = interp(phi_odat, phi_raw, kin_coord)
    
idat = fda.dt_movingavg(hstack(lidat).T, 30)
odat = fda.dt_movingavg(hstack(lodat).T, 30)
init_mapping_r = dot(pinv(idat, rcond=1e-8), odat).T



# verify that map is close to 1 !!! (-> mostly true for positions; not so much for velocities!)
figure(figsize=(12,6))
subplot(1,2,1)
pcolor(init_mapping_r[::-1,:]), clim(-1,1)
title('map from all data')
subplot(1,2,2)
pcolor(im_r_m[::-1, :]), clim(-1,1)
title('avg. from bootstrapping')


bootstrapping...
==================================================
..................................................done
Out[9]:
<matplotlib.text.Text at 0x34205f50>

In [10]:
dat = ws9.d1d_r_dt
idx = 2
m1 = dot(pinv(dat[:, idx::50]), dat[:, idx+1::50])
figure()
pcolor(m1), clim(-1,1)
colorbar()


Out[10]:
<matplotlib.colorbar.Colorbar instance at 0x341f0e60>

In [11]:
# sanity check
figure(), plot(idat_raw[0,:])
print idat_raw.shape
plot(ws9.d1d_r[-326:, 0],'rd')
title('sanity check: comparison of different views of the same data')
#ws9.d1d_r.shape


(46, 326)
Out[11]:
<matplotlib.text.Text at 0x2dfc21d0>

-space left-


In [12]:
# compute baseline 
# step = 1203 has to be defined somewhere else

baseline_r = roll(vstack([ws9.d1d_r_trend[step,x*ws9.nps:(x+1)*ws9.nps] for x in ws9.FM_CoM_sel_idx]), -1, axis=1)
baseline_l = roll(vstack([ws9.d1d_l_trend[step,x*ws9.nps:(x+1)*ws9.nps] for x in ws9.FM_CoM_sel_idx]), -1, axis=1)
print "NOTE: baseline data is already 'rolled' - first index [0] corresponds to first section to predict!"
# add belt speed
vBelt = mean([d.vBelt for d in ws9.SlipData])
baseline_r[1, :] += vBelt
baseline_l[1, :] += vBelt

fmdl_preds = []
apexstate = idat[step, :]
# compute predictions
for mdl in ws9.fmodels_r:
    scmdl = dot(mdl, init_mapping_r) # map to 1st section -> map to requested section
    scmdl = dot(mdl, im_r_m) # map to 1st section -> map to requested section
    #scmdl = mdl # omit initial mapping from apex state -> section after apex
    pred = dot(scmdl, apexstate)
    fmdl_preds.append(pred)


fmdl_pred_r = vstack(fmdl_preds)
com_pred_r_dt = fmdl_pred_r[:, ws9.FM_CoM_sel_idx]
com_pred_r = com_pred_r_dt + baseline_r[:, :com_pred_r_dt.shape[0]].T

# include SLIP prediction
# SLIP_IC = apexstate[


NOTE: baseline data is already 'rolled' - first index [0] corresponds to first section to predict!

In [13]:
if not hasattr(ws9, 'ks'):
    ws9.ks = mio.KinData()
    
ws9.ks.load(ws9.subject, ws9.ttype) # subject in [1,2,3,7], ttype=1
ws9.ks.selection = ['com_x', 'com_y', 'com_z', 'r_anl_y - com_y', 'r_anl_z - com_z', 'r_anl_x - com_x']

k_apex = ws9.ks.get_kin_apex(phases = ws9.k.all_phases_r)
aka = hstack(k_apex).T[:, 2:]
kin_labels = ws9.ks.selection[2:] + ['v_' + x for x in ws9.ks.selection]
print "aka.shape:", aka.shape
print kin_labels
aka_s = aka[:, reord_idx(kin_labels)] # apex states from "kin at apex" (quadratic interpolation) INCLUDING vertical velocity!

# find index of v_com_z
for idx, lbl_idx in enumerate(reord_idx(kin_labels)):
    if kin_labels[lbl_idx] == 'v_com_z':
        break
        
print "identified index:", lbl_idx
aka_sx = hstack([aka_s[:, :lbl_idx], aka_s[:, lbl_idx + 1:]])
# detrend non-CoM states!
aka_sx[:, 3:] = fda.dt_movingavg(aka_sx[:, 3:], 30)


aka.shape: (1957, 10)
['com_z', 'r_anl_y - com_y', 'r_anl_z - com_z', 'r_anl_x - com_x', 'v_com_x', 'v_com_y', 'v_com_z', 'v_r_anl_y - com_y', 'v_r_anl_z - com_z', 'v_r_anl_x - com_x']
identified index: 6

In [14]:
print [(rep, kin_labels[val]) for rep, val in enumerate(reord_idx(kin_labels))]
print "v_com_z?"
print aka_sx[step, : ]
print aka_s[step, : ]


[(0, 'com_z'), (1, 'v_com_y'), (2, 'v_com_x'), (3, 'r_anl_y - com_y'), (4, 'r_anl_z - com_z'), (5, 'r_anl_x - com_x'), (6, 'v_com_z'), (7, 'v_r_anl_y - com_y'), (8, 'v_r_anl_z - com_z'), (9, 'v_r_anl_x - com_x')]
v_com_z?
[  1.00827521e+00   8.69311887e-02   3.03654816e-02   1.35319164e-02
   1.98239189e-03   9.47087260e-03   2.44755353e-02   4.18915697e-02
  -5.79256318e-04]
[  1.00827521e+00   8.69311887e-02   3.03654816e-02   1.71257051e-01
  -8.90476340e-01   1.19425142e-01  -9.77565699e-07   1.94319022e+00
  -2.49360339e-01  -1.97292780e-01]

In [15]:
print "reference state:", ws9.ref_state_r
CoM_exp = aka_sx[step, :].copy()# + baseline_r[:,0]

print "-------------- Comparison of 'apex state' with regularly sampled data [y, vx, vz]: ------- "
print ' '.join([str(elem) for elem in CoM_exp[:3]])
print ws9.d1d_r[step, 0], ws9.d1d_r[step, 50*23], ws9.d1d_r[step, 50*22]
print "-------------------------------------------------------------------------------------------"

CoM_exp[1] += vBelt
#CoM_exp = aka[1203, ws9.FM_CoM_sel_idx[array([0,1,3])]]# + baseline_r[:,0]
#CoM_exp[1] += vBelt
#print CoM_exp
SLIP_IC = CoM_exp
print "IC:", SLIP_IC
cSLIP_r = get_auto_sys(ws9.ref_param_r, ws9.ref_param_l, ws9.ref_state_r, ws9.ref_state_l,
    ws9.ctrl_r, ws9.ctrl_l, ws9.nmap_r, ws9.nmap_l, ws9.ref_addDict, full_info=True)
fs, (sim_t, sim_state) = cSLIP_r(SLIP_IC)


reference state: [ 1.00689746  2.87786266  0.04280586  0.          0.          0.          0.
  0.          0.        ]
-------------- Comparison of 'apex state' with regularly sampled data [y, vx, vz]: ------- 
1.00827520999 0.0869311886827 0.0303654816247
1.00826061729 0.0870059567409 0.0303776225382
-------------------------------------------------------------------------------------------
IC: [  1.00827521e+00   2.89490769e+00   3.03654816e-02   1.35319164e-02
   1.98239189e-03   9.47087260e-03   2.44755353e-02   4.18915697e-02
  -5.79256318e-04]

TODO:

compute phase for SLIP! to content


In [16]:
phi0, T_sim = getPhase(SLIP_IC, cSLIP_r)
print sim_state.shape, sim_t.shape


(751, 6) (751,)

In [17]:
_, (ref_sim_t, ref_sim_state) = cSLIP_r(ws9.ref_state_r)
ref_sim_phase = ref_sim_t / ref_sim_t[-1] * 2*pi


#fs, (sim_t, sim_state) = cSLIP_r(SLIP_IC)
phi0, T_sim = getPhase(SLIP_IC, cSLIP_r)
phi_mdl = sim_t / T_sim * 2*pi + phi0
# adapt t_sim_50 such that these points have the same phase as the experimental data
t_sim_50 = linspace(0, sim_t[-1], 50, endpoint=False)
phi_50 = (arange(25) + 1) * .02 * 2* pi

vx_sim = interp(phi_50, phi_mdl, sim_state[:, 3])
vx_sim_ref = interp(phi_50, ref_sim_phase, ref_sim_state[:, 3])
y_sim = interp(phi_50, phi_mdl, sim_state[:, 1])
y_sim_ref = interp(phi_50, ref_sim_phase, ref_sim_state[:, 1])
vz_sim = interp(phi_50, phi_mdl, sim_state[:, 5])
vz_sim_ref = interp(phi_50, ref_sim_phase, ref_sim_state[:, 5])
#plot(vx_sim[1:], 'm', label='controlled SLIP') # old version
#y_sim = interp(t_sim_50, sim_t, sim_state[:, 1])



figure(19,figsize=(12,10))
clf()

subplot(3,1,1) # vx
plot(baseline_r[1, :],'r', label='baseline (average motion)')
plot(vx_sim_ref,'r--', label='SLIP periodic orbit')
plot(com_pred_r_dt[:,1] + 3,'b', label='deviation from baseline (Floquet model)')
plot([0, 24], [3, 3],'b--')
plot(com_pred_r[:,1],'k--', label='predicted (Floquet model + baseline)')
vx_slice = slice(ws9.FM_CoM_sel_idx[1] * ws9.nps , (ws9.FM_CoM_sel_idx[1] + 1) * ws9.nps)
vz_slice = slice(ws9.FM_CoM_sel_idx[3] * ws9.nps , (ws9.FM_CoM_sel_idx[3] + 1) * ws9.nps)
plot(0, apexstate[ws9.FM_CoM_sel_idx[1]] + baseline_r[1, 0], 'gd', label='apex state (Floquet model IC)')
ylim(2.5, 3.1)
plot(vx_sim[0:], 'm')



vx_exp = ws9.d1d_r[step, vx_slice] + vBelt
y_exp = ws9.d1d_r[step, :50]
vz_exp = ws9.d1d_r[step, vz_slice]
#print "NOTE - vx_exp is *not* yet rolled by 1 frame!"
plot(vx_exp[1:],'k', label='experimental data')
print "belt speed is ", vBelt
legend()
title('horizontal speed')


subplot(3,1,2) # y
plot(y_sim[0:], 'm', label='controlled SLIP')
plot(y_sim_ref,'r--', label='SLIP periodic orbit')
#plot(y_sim[1:], 'm')
plot(y_exp[1:],'k', label='experimental data')
plot(com_pred_r[:,0],'k--', label='predicted (Floquet model + baseline)')
plot(baseline_r[0,:],'r', label='baseline')
title('vertical position')

subplot(3,1,3) #vz
plot(vz_sim[0:], 'm', label='controlled SLIP')
plot(vz_sim_ref,'r--', label='SLIP periodic orbit')
#plot(vz_sim[1:], 'm')
plot(vz_exp[1:],'k', label='experimental data')
plot(com_pred_r[:,3],'k--', label='predicted (Floquet model + baseline)')
plot(baseline_r[3,:],'r', label='baseline')
title('lateral speed')


belt speed is  2.80797649746
Out[17]:
<matplotlib.text.Text at 0x62857ed0>

In [18]:
# sanity check
print "selected step:", step
figure()
vx_slice = slice(ws9.FM_CoM_sel_idx[1] * ws9.nps , (ws9.FM_CoM_sel_idx[1] + 1) * ws9.nps)
plot(hstack([ws9.d1d_r[x, vx_slice] for x in range(1200, 1207)]), 'b', label='experimental data')
xval = 50 * arange(7)
delta=0
plot(hstack([ws9.d1d_r_dt[x, vx_slice] + ws9.d1d_r_trend[x, vx_slice] for x in range(1200, 1207)]), 'r--', label='exp: trend + detrend')
plot(xval, idat[range(1200 + delta,1207 + delta), ws9.FM_CoM_sel_idx[1]],'rd', label='ICs for floquet model')
plot(hstack([ws9.d1d_r_trend[x, vx_slice] for x in range(1200, 1207)]), 'k--', label='exp: baseline')
plot(hstack([ws9.d1d_r_dt[x, vx_slice] for x in range(1200, 1207)]), 'g--', label='exp: deviation from baseline')
legend()


selected step: 1100
Out[18]:
<matplotlib.legend.Legend at 0x62ad0290>

In [19]:
# create controlled "left" and "right" SLIP (model that starts with left and right step)
cSLIP_r = get_auto_sys(ws9.ref_param_r, ws9.ref_param_l, ws9.ref_state_r, ws9.ref_state_l,
    ws9.ctrl_r, ws9.ctrl_l, ws9.nmap_r, ws9.nmap_l, ws9.ref_addDict, full_info=True)
cSLIP_l = get_auto_sys(ws9.ref_param_l, ws9.ref_param_r,  ws9.ref_state_l, ws9.ref_state_r,
    ws9.ctrl_l, ws9.ctrl_r,  ws9.nmap_l, ws9.nmap_r, ws9.ref_addDict, full_info=True)

In [19]:


In [20]:
# get phase of apex
phi_r = mod(ws9.a_phi_apex_r[step], 2*pi)

In [21]:
# compute predictions
ws9.fmodels_r[0].shape


Out[21]:
(46, 46)

In [22]:
figure()
plot(baseline_r[2, :],'b.-')
plot(baseline_l[2, :],'b--')
plot([24,24],[-.5, .5],'r--')
plot([0,50],[0,0],'k--')


Out[22]:
[<matplotlib.lines.Line2D at 0x62f92d90>]

In [23]:
x = arange(12).reshape(3,4)

In [24]:
print x
print roll(x, 1, axis=1)


[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
[[ 3  0  1  2]
 [ 7  4  5  6]
 [11  8  9 10]]

In [25]:
ws9.display()


FM_CoM_sel_idx    array (4,)   
SlipData          list (6)   
_saveables        list (8)   
a_phi_apex_l      array (1961,)   
a_phi_apex_r      array (1959,)   
ctrl_l            array (5, 9)   
ctrl_r            array (5, 9)   
d1d_l             array (1957, 2300)     
d1d_l_dt          array (1957, 2300)     
d1d_l_trend       array (1957, 2300)     
d1d_r             array (1957, 2300)     
d1d_r_dt          array (1957, 2300)     
d1d_r_trend       array (1957, 2300)     
dataset_l         <class 'mutils.io.saveable'>               
dataset_r         <class 'mutils.io.saveable'>               
fmodels_l         list (25)   
fmodels_r         list (25)   
k                 <class 'mutils.io.saveable'>               
k9                <class 'mutils.io.KinData'>              
kdata_full        <class 'mutils.io.saveable'>               
ks                <class 'mutils.io.KinData'>              
n_sct             <type 'int'>   
nmap_l            array (6, 9)   
nmap_r            array (6, 9)   
nps               <type 'int'>   
phases_d1d_l      list (6)   
phases_d1d_r      list (6)   
phi_apex_l        <type 'numpy.float64'>         
phi_apex_r        <type 'numpy.float64'>         
ref_addDict       <type 'dict'>   
ref_param_l       array (5,)   
ref_param_r       array (5,)   
ref_state_l       array (9,)   
ref_state_r       array (9,)   
s_phi_apex_l      <type 'numpy.float64'>         
s_phi_apex_r      <type 'numpy.float64'>         
stride_idcs       list (4)   
subject           <type 'int'>   
ttype             <type 'int'>   

In [26]:
k = mio.KinData()
k.load(2, 1) # subject in [1,2,3,7], ttype=1

#SlipData = [mi.Struct(mio.mload('../data/2013-newSlip/SLIP_s%it%ir%i.dict' % (ws9.subject, ws9.ttype, rep)))
#           for rep in k9.reps]

k.selection = ['com_x', 'com_y', 'com_z', 'r_anl_y - com_y', 'r_anl_z - com_z', 'r_anl_x - com_x', 'l_anl_y - com_y', 'l_anl_z - com_z', 'l_anl_x - com_x',]
d1d = k.make_1D(nps=50)[:, 100:]

In [27]:
d1d -= mean(d1d, axis=0)
u,s,v = svd(d1d.T, full_matrices = False)
print v.shape


(800, 1939)

In [28]:
figure()
for rep in range(4):    
    subplot(4,1,1 + rep)
    plot(v[rep,:],'.')
    plot([0,1940],[0,0],'k--')
    ylabel('PC ' + str(rep + 1))
    if rep==0:
        title('scores on first principal components on CoM + Ankles-System')



In [29]:
SlipData = [mi.Struct(mio.mload('../data/2013-newSlip/SLIP_s%it%ir%i.dict' % (2, 1, rep)))
           for rep in k.reps]

d9 = build_dataset(k, SlipData) 
pr = d9.all_param_r.copy()
pr -= mean(pr, axis=0)
pr /= std(pr, axis=0)
u,s,v = svd(pr.T, full_matrices=False)

In [30]:
figure()
for rep in range(5):    
    subplot(5,1,1 + rep)
    plot(v[rep,:],'r.')
    plot([0,1940],[0,0],'k--')
    ylabel('PC ' + str(rep + 1))
    if rep==0:
        title('scores on first principal components on SLIP parameters')

print "s**2 normalized:", s**2 / sum(s**2)


s**2 normalized: [ 0.64095676  0.20665128  0.08243219  0.04740831  0.02255146]

In [31]:
ws9.ref_state_r
dist_state = ws9.ref_state_r.copy()
dist_state[2] += .5 # lateral velocity
fs = dist_state.copy()
all_simt, all_sims = [], []
lasttime = 0
lastpos = [0, 0, 0]
for rep in range(10):
    fs, (sim_t, sim_states) = cSLIP_r(fs)    
    all_simt.append(sim_t + lasttime)    
    sim_states[:, :3] += lastpos
    all_sims.append(sim_states)    
    lasttime = sim_t[-1]
    lastpos = sim_states[-1,:3]
    
sim_states = vstack(all_sims)
sim_t = hstack(all_simt) #

In [133]:



Out[133]:
(9,)

In [32]:
figure()
plot(sim_states[:,0], sim_states[:,2],'r.')


Out[32]:
[<matplotlib.lines.Line2D at 0x8cb49f90>]

In [119]:
eig_nps = 4
k3s = ws9.k9.make_1D(nps=eig_nps)
k3s = fda.dt_movingavg(k3s[:, eig_nps * 2:], 30)
k3s.shape


Out[119]:
(1939, 184)

In [112]:
138 / 3


Out[112]:
46

In [ ]:
### quickly compare EV's of multi-section map with J of controlled SLIP

In [141]:
cr = lambda x: cSLIP_r(x)[0]
J = mi.calcJacobian(cr, ws9.ref_state_r)

In [120]:
_, m1, idcs = fda.fitData(k3s[:, ::eig_nps], k3s[:, 1::eig_nps],  nps=1, nrep=100, rcond=1e-6)
_, m2, idcs = fda.fitData(k3s[:, 1::eig_nps], k3s[:, 2::eig_nps],  nps=1, nrep=100, rcond=1e-6)
_, m3, idcs = fda.fitData(k3s[:, 2::eig_nps], k3s[:, 3::eig_nps],  nps=1, nrep=100, rcond=1e-6)
_, m4, idcs = fda.fitData(k3s[:-1, 3::eig_nps], k3s[1:, 0::eig_nps],  nps=1, nrep=100, rcond=1e-6)

In [123]:
m = [reduce(dot, [x1.T, x2.T, x3.T, x4.T]) for x1,x2,x3, x4 in zip(m1, m2, m3, m4)]

In [147]:
import libshai.util as ut
vi = ut.VisEig(127, False)
for A in m:
    vi.add(eig(A)[0])
    
figure(figsize=(8,7))
vi.vis1()
xlim(-1,1)
ylim(-1,1)
xlabel('real part')
ylabel('imaginary part')
#ncnt = 0
#for ev in eig(J)[0]:
#    lbl = None if ncnt > 0 else "Eigenvalues of controlled ankle-SLIP"
#    plot(ev.real, ev.imag, 'rd', label=lbl)
#    ncnt += 1
title('eigenvalue distribution of return maps\nsubject 2')
#legend()


Out[147]:
<matplotlib.text.Text at 0x8e242ed0>

In [130]:
print ws9.k9.subject
print ws9.subject


2
2

In [143]:
figure()
for ev in eig(J)[0]:
    plot(ev.real, ev.imag, 'rd')

ylim(-1,1)
xlim(-1,1)
axis('equal')


Out[143]:
(-0.20000000000000001,
 0.29999999999999999,
 -0.30000000000000004,
 0.30000000000000004)

In [ ]:
get_auto_sys(ws9.ref_param_r, ws9.ref_param_l, ws9.ref_state_r, ws9.ref_state_l,
    ws9.ctrl_r, ws9.ctrl_l, ws9.nmap_r, ws9.nmap_l, ws9.ref_addDict, full_info=True)
fs, (sim_t, sim_state) = cSLIP_r(SLIP_IC)